diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml new file mode 100644 index 0000000..abd123d --- /dev/null +++ b/.github/workflows/pytest.yml @@ -0,0 +1,29 @@ +name: Run Tests + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v5 + + - name: Install uv + uses: astral-sh/setup-uv@v7 + + - name: Set up Python + run: uv python install + + - name: Install dependencies with uv + run: uv sync --all-extras --dev + - name: install local + run: uv pip install --editable ./ + + - name: Run tests with uv + run: uv run pytest \ No newline at end of file diff --git a/.gitignore b/.gitignore index a581e6c..3d3243a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,8 @@ jsonschema .DS_Store empty_log_process_temp.py +tests/**/bids/ +tests/test_main_functionality/data/projects/test-project/sub-100 # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/docs/configuration.md b/docs/configuration.md index 023e131..17dd391 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -17,8 +17,6 @@ lslautobids gen-dv-config ``` _Currently, the package doesn't allow you to have multiple dataverse configurations. This will be added in future versions and can be easily adapted_ -However for testing purposes, we create a separate test configuration file `~/.config/lslautobids/test-autobids_config.yaml` which is used when running the tests. - #### Project Configuration (`gen_project_config.py`) This module generates a project-specific configuration file in TOML format. This file is stored in the `projects//_config.toml` file and contains: - Project metadata: Title, description, license, and authors, etc. diff --git a/docs/developers_documentation.md b/docs/developers_documentation.md index adec2d1..7ccca0f 100644 --- a/docs/developers_documentation.md +++ b/docs/developers_documentation.md @@ -92,9 +92,7 @@ The command to generate the dataverse configuration file is: ``` lslautobids gen-dv-config ``` -_Currently, the package doesn't allow you to have multiple dataverse configurations. This will be added in future versions and can be easily adapted_ - -However for testing purposes, we create a separate test configuration file `~/.config/lslautobids/test-autobids_config.yaml` which is used when running the tests. +_Currently, the package doesn't allow you to have multiple dataverse configurations. This will be added in future versions. #### 2. Project Configuration (`gen_project_config.py`) This module generates a project-specific configuration file in TOML format. This file is stored in the `projects//_config.toml` file and contains: diff --git a/docs/testing.md b/docs/testing.md index 4151bf2..d6673b7 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -14,7 +14,6 @@ Tests will be added continuously as new features are added and existing features ### Running Tests -To run the tests, navigate to the `tests/` directory and execute: -`python tests/run_all_tests.py` +To run the tests, we recommend to use `uv run pytest` (caveat, for some reason sometimes tests fail if they are all run at the same time. you can then run them via `uv run pytest tests/testcase/test_main_functionality` and they will work). These tests ensure that each component functions as expected and that the overall pipeline works seamlessly. This tests will also be triggered automatically on each push or PR to the main repository using GitHub Actions. \ No newline at end of file diff --git a/lslautobids/config_globals.py b/lslautobids/config_globals.py index 0c0c016..6b4b9ed 100644 --- a/lslautobids/config_globals.py +++ b/lslautobids/config_globals.py @@ -13,6 +13,7 @@ def __init__(self): "redo_bids_conversion": False, "reupload": False, "redo_other_pc": False, + "push_to_dataverse": True, } def init(self, args): @@ -55,7 +56,7 @@ def parse_yaml_file(yaml_file): # Determine config paty based on context if "pytest" in sys.modules: - config_file = os.path.join(os.path.expanduser("~"), ".config/lslautobids/test-autobids_config.yaml") + config_file = "tests/pytest-autobids_config.yaml" else: config_file = os.path.join(os.path.expanduser("~"), ".config/lslautobids/autobids_config.yaml") config = parse_yaml_file(config_file) diff --git a/lslautobids/convert_to_bids_and_upload.py b/lslautobids/convert_to_bids_and_upload.py index 092f9b8..2da8b19 100644 --- a/lslautobids/convert_to_bids_and_upload.py +++ b/lslautobids/convert_to_bids_and_upload.py @@ -364,7 +364,7 @@ def convert_to_bids(self, xdf_path,subject_id,session_id, run_id, task_id,other, # Validate BIDS data logger.info("Validating BIDS data...") # Validate the BIDS data - val = self.validate_bids(bids_root+project_name,subject_id,session_id, logger) + val = self.validate_bids(os.path.join(bids_root,project_name),subject_id,session_id, logger) return val def validate_bids(self,bids_path,subject_id,session_id, logger): @@ -482,22 +482,23 @@ def bids_process_and_upload(processed_files,logger): bids.populate_dataset_description_json(project_name, logger) logger.info('Generating metadatafiles........') generate_json_file(project_name, logger) - logger.info('Generating dataverse dataset........') - doi, status = create_dataverse(project_name) - logger.info("Creating and adding files to Dataverse dataset...") - create_and_add_files_to_datalad_dataset(bids_root+project_name,status, logger) + logger.info("Creating and adding files to Datalad dataset...") + create_and_add_files_to_datalad_dataset(os.path.join(bids_root,project_name),logger) - if status == 0: - logger.info('Linking dataverse dataset with datalad') - add_sibling_dataverse_in_folder(doi, logger) - - if cli_args.yes: - logger.info('Pushing files to dataverse........') - push_files_to_dataverse(project_name, logger) - else: - user_input = get_user_input("Do you want to push the files to Dataverse? ",logger) + if cli_args.push_to_dataverse: + logger.info('Generating dataverse dataset........') + doi, status = create_dataverse(project_name, logger) + if status == 0: # run only if a new dataverse was created + logger.info('Linking dataverse dataset with datalad') + add_sibling_dataverse_in_folder(doi, logger) + + if cli_args.yes: + user_input = "y" + else: + user_input = get_user_input("Do you want to push the files to Dataverse? ",logger) + if user_input == "y": logger.info('Pushing files to dataverse........') push_files_to_dataverse(project_name, logger) @@ -505,3 +506,5 @@ def bids_process_and_upload(processed_files,logger): logger.info("Program aborted.") else: logger.error("Invalid Input.") + else: + logger.info('cli.push_to_dataverse was false, not pushing.') diff --git a/lslautobids/datalad_create.py b/lslautobids/datalad_create.py index d377ff5..830c8d0 100644 --- a/lslautobids/datalad_create.py +++ b/lslautobids/datalad_create.py @@ -2,29 +2,33 @@ import os -def create_and_add_files_to_datalad_dataset(dataset_path,flag, logger): +def create_and_add_files_to_datalad_dataset(dataset_path,logger): message = "LSL Auto BIDS: new files found and added" - if flag==0: + #if flag==0: + + try: + dl.Dataset(dataset_path) + except: message ="LSL Auto BIDS: new datalad dataset created" # Create a new dataset logger.info('Creating a new datalad dataset........') try: dl.create(dataset_path, force=True) # files already exist, so we eforce it + + # make sure only large files are saved + with open(os.path.join(dataset_path,".gitattributes"), "a") as f: + f.write("* annex.largefiles=largerthan=100kb") + f.write("\n*.csv annex.largefiles=nothing") + f.write("\n*.log annex.largefiles=nothing") + f.write("\n*.tsv annex.largefiles=nothing") + f.write("\n*.md annex.largefiles=nothing") + f.write("\n*.json annex.largefiles=nothing") + except: logger.info("Could not create a new dataset, maybe it exists already?") - # Commit changes - # Change to dataset path - os.chdir(dataset_path) - if flag==0: - # needed to modify participants.tsv etc. later - with open(os.path.join(dataset_path,".gitattributes"), "a") as f: - f.write("* annex.largefiles=largerthan=100kb") - f.write("\n*.csv annex.largefiles=nothing") - f.write("\n*.log annex.largefiles=nothing") - f.write("\n*.tsv annex.largefiles=nothing") - f.write("\n*.md annex.largefiles=nothing") - f.write("\n*.json annex.largefiles=nothing") + + # commit current files logger.info('Committing current changes........') - dl.save(path = '.', message=message) + dl.save(path = dataset_path, message=message) diff --git a/lslautobids/dataverse_dataset_create.py b/lslautobids/dataverse_dataset_create.py index c381305..66285b8 100644 --- a/lslautobids/dataverse_dataset_create.py +++ b/lslautobids/dataverse_dataset_create.py @@ -12,7 +12,7 @@ logger = logging.getLogger(__name__) logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') -def create_dataverse(project_name): +def create_dataverse(project_name, logger): """ Creates a Dataverse dataset and returns the PID and dataset ID. diff --git a/pyproject.toml b/pyproject.toml index 878fc0c..c81115c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,5 +6,11 @@ build-backend = "setuptools.build_meta" # Ref: https://github.com/codespell-project/codespell#using-a-config-file skip = '.git*,*.svg,*.bib' check-hidden = true + +[dependency-groups] +dev = [ + "git-annex>=10.20251114", + "pytest>=9.0.1", +] # ignore-regex = '' # ignore-words-list = '' diff --git a/tests/testcases/test_old_suffix/test_old_suffix.py b/tests/conftest.py similarity index 54% rename from tests/testcases/test_old_suffix/test_old_suffix.py rename to tests/conftest.py index 3f49cfe..3523e2e 100644 --- a/tests/testcases/test_old_suffix/test_old_suffix.py +++ b/tests/conftest.py @@ -1,19 +1,12 @@ -import os -import sys import pytest -import yaml - - -# Compute project root (two levels up from current test.py) -PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) +import sys,os +PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__)) if PROJECT_ROOT not in sys.path: sys.path.insert(0, PROJECT_ROOT) +import yaml -from test_utils.path_config import get_root_paths +from path_config import get_root_paths -# Print test file name for traceability -test_file_name = os.path.basename(__file__) -print(f" Running tests in {test_file_name}") # Dummy CLI argument simulation class DummyCLIArgs: @@ -22,11 +15,11 @@ def __init__(self): self.yes = True self.redo_bids_conversion = False self.redo_other_pc = False + self.push_to_dataverse = False def init(self, args): # you can store the args or ignore pass - @pytest.fixture(scope="function") def setup_project(monkeypatch): """ @@ -38,13 +31,14 @@ def setup_project(monkeypatch): project_name = dummy_cli_args.project_name # Ensure directory exists - os.makedirs(paths["project_root"], exist_ok=True) + #os.makedirs(paths["project_root"], exist_ok=True) from lslautobids.gen_project_config import main as gen_project_config_main # Create dummy user config for the test - config_file_test = os.path.join(os.path.expanduser("~"),'.config/lslautobids/test-autobids_config.yaml') - os.makedirs(os.path.dirname(config_file_test), exist_ok=True) + config_file_test = ("tests/pytest-autobids_config.yaml") + + #os.makedirs(os.path.dirname(config_file_test), exist_ok=True) config_data = { "PROJECT_ROOT": paths["project_root"], "BIDS_ROOT": paths["bids_root"], @@ -60,6 +54,10 @@ def setup_project(monkeypatch): monkeypatch.setattr("lslautobids.config_globals.project_root", paths["project_root"]) monkeypatch.setattr("lslautobids.config_globals.bids_root", paths["bids_root"]) monkeypatch.setattr("lslautobids.config_globals.project_other_root", paths["project_other_root"]) + monkeypatch.setattr("lslautobids.config_globals.dataverse_base_url","https://demodarus.izus.uni-stuttgart.de/") + monkeypatch.setattr("lslautobids.config_globals.api_key","8b6c479e-e85b-4edb-9b8a-5305a9976875") + monkeypatch.setattr("lslautobids.config_globals.parent_dataverse_name","s-ccs") + #monkeypatch.setattr("lslautobids.config_globals.parent_dataverse_name","Institute for Visualization and Interactive Systems") monkeypatch.setattr("lslautobids.config_globals.cli_args", dummy_cli_args) monkeypatch.setattr("lslautobids.config_globals.config_file", config_file_test) @@ -72,32 +70,7 @@ def setup_project(monkeypatch): gen_project_config_main() - return paths, project_name - - -@pytest.mark.filterwarnings("ignore::DeprecationWarning") -def test_process_new_files_with_old_suffix(setup_project, monkeypatch): - """ - Expect the main pipeline to raise RuntimeError when duplicate files are found. - """ - paths, project_name = setup_project - - project_toml_path = os.path.join(paths["project_root"], project_name, f"{project_name}_config.toml") - - # Reset sys.argv to something that lslautobids.main.main() expects - sys.argv = [ - "lslautobids.main", - "-p", project_name, - # other args expected by lslautobids.main.main - ] - - dummy_cli_args = DummyCLIArgs() - monkeypatch.setattr("lslautobids.config_globals.cli_args", dummy_cli_args) - - # Import and run main pipeline, expect a RuntimeError - from lslautobids.main import main as runlslautobids - with pytest.raises(SystemExit, match="Duplicate file detected. Please check the file manually."): - runlslautobids() - - + yield project_name + # crashdown + #os.remove(config_file_test) \ No newline at end of file diff --git a/tests/data/projects/test-project/test-project_config.toml b/tests/data/projects/test-project/test-project_config.toml new file mode 100644 index 0000000..b1d78a6 --- /dev/null +++ b/tests/data/projects/test-project/test-project_config.toml @@ -0,0 +1,27 @@ + + # This is the project configuration file - This configuration can be customized for each project + + [AuthorsInfo] + authors = "John Doe, Lina Doe" # List of authors separated by commas + affiliation = "University of Stuttgart, University of Stuttgart" # Affiliation of the authors in the same order as authors + email = "john@gmail.com" # Contact email of the authors in the same order as authors + + [DataverseDataset] + title = "Convert XDF to BIDS" # Title of the Dataverse dataset. This gets updated automatically by the project name. + datasetDescription = "This is a test project to set up the pipeline to convert XDF to BIDS." # Description of the dataset. This description will appear in the dataset.json file which then eventually gets displayed in the dataverse metadata + license = "MIT License" # License for the dataset, e.g. "CC0", "CC-BY-4.0", "ODC-By-1.0", "PDDL-1.0", "ODC-PDDL-1.0", "MIT License" + subject = ["Medicine, Health and Life Sciences","Engineering"] # List of subjects related to the dataset required for dataverse metadata + pid = '' # Persistent identifier for the dataset, e.g. DOI or Handle. This will be updated automatically after creating the dataset in dataverse. + + [OtherFilesInfo] + otherFilesUsed = true # Set to true if you want to include other (non-eeg-files) files (experiment files, other modalities like eye tracking) in the dataset, else false + expectedOtherFiles = [".edf", ".csv", "_labnotebook.tsv", "_participantform.tsv"] # List of expected other file extensions. Only the expected files will be copied to the beh folder in BIDS dataset. Give an empty list [] if you don't want any other files to be in the dataset. In this case only experiment files will be zipeed and copied to the misc folder in BIDS dataset. + + [FileSelection] + ignoreSubjects = ['sub-777'] # List of subjects to ignore during the conversion - Leave empty to include all subjects. Changing this value will not delete already existing subjects. + excludeTasks = ['sampletask'] # List of tasks to exclude from the conversion for all subjects - Leave empty to include all tasks. Changing this value will not delete already existing tasks. + + [BidsConfig] + anonymizationNumber = 123 # This is an anomization number that will be added to the recording date of all subjects. + + \ No newline at end of file diff --git a/tests/path_config.py b/tests/path_config.py new file mode 100644 index 0000000..cc0405f --- /dev/null +++ b/tests/path_config.py @@ -0,0 +1,35 @@ +import os + +def get_root_paths(test_file: str): + """ + Given a test file (__file__), return relevant test root paths. + """ + # Use the test_file argument, not __file__ from path_config.py + test_folder = os.path.basename(os.path.dirname(test_file)) + + # Go up to the test folder's path and into its `data/` directory + base_dir = os.path.abspath(os.path.join(os.path.dirname(test_file), "data")) + + print(f'The base dir in the get_roots_path function is "{base_dir}"') + return { + "project_root": os.path.join(base_dir, "projects"), + "bids_root": os.path.join(base_dir, "bids"), + "project_other_root": os.path.join(base_dir, "project_other"), + } + + + +def monkeypatch_paths(monkeypatch,paths): + monkeypatch.setattr("lslautobids.config_globals.project_root", paths["project_root"]) + monkeypatch.setattr("lslautobids.convert_to_bids_and_upload.project_root", paths["project_root"]) + monkeypatch.setattr("lslautobids.generate_dataset_json.project_root", paths["project_root"]) + monkeypatch.setattr("lslautobids.main.project_root", paths["project_root"]) + monkeypatch.setattr("lslautobids.processing_new_files.project_root", paths["project_root"]) + + monkeypatch.setattr("lslautobids.config_globals.bids_root", paths["bids_root"]) + monkeypatch.setattr("lslautobids.convert_to_bids_and_upload.bids_root", paths["bids_root"]) + monkeypatch.setattr("lslautobids.main.bids_root", paths["bids_root"]) + + monkeypatch.setattr("lslautobids.config_logger.bids_root", paths["bids_root"]) + monkeypatch.setattr("lslautobids.config_globals.project_other_root", paths["project_other_root"]) + monkeypatch.setattr("lslautobids.convert_to_bids_and_upload.project_other_root", paths["project_other_root"]) \ No newline at end of file diff --git a/tests/pytest-autobids_config.yaml b/tests/pytest-autobids_config.yaml new file mode 100644 index 0000000..bd9dd5b --- /dev/null +++ b/tests/pytest-autobids_config.yaml @@ -0,0 +1,3 @@ +BIDS_ROOT: /home/behinger/projects/LSLAutoBIDS/tests/data/bids +PROJECT_OTHER_ROOT: /home/behinger/projects/LSLAutoBIDS/tests/data/project_other +PROJECT_ROOT: /home/behinger/projects/LSLAutoBIDS/tests/data/projects diff --git a/tests/run_all_tests.py b/tests/run_all_tests.py deleted file mode 100644 index c2cbc31..0000000 --- a/tests/run_all_tests.py +++ /dev/null @@ -1,29 +0,0 @@ -import os -import subprocess -import sys - -# --- Setup --- -BASE_DIR = os.path.dirname(__file__) # base tests directory -TESTCASES_DIR = os.path.join(BASE_DIR, "testcases") -TEST_UTILS_DIR = os.path.join(BASE_DIR, "test_utils") - -# Make both testcases and test_utils importable -sys.path.insert(0, TESTCASES_DIR) -sys.path.insert(0, TEST_UTILS_DIR) - - -print("Searching for test directories...\n") - -for folder in os.listdir(TESTCASES_DIR): - folder_path = os.path.join(TESTCASES_DIR, folder) - - if ( - folder.startswith("test_") - and os.path.isdir(folder_path) - and any(f.endswith(".py") for f in os.listdir(folder_path)) - and os.path.exists(os.path.join(folder_path, "data")) - ): - print(f"Running tests in: {folder} which has folder path {folder_path}") - subprocess.run(["pytest", folder_path]) - else: - print(f"Skipping: {folder} (no tests file or data). Recheck if the test files are in place or data folder is missing.") diff --git a/tests/testcases/test_old_suffix/__init__.py b/tests/test_main_functionality/__init__.py similarity index 100% rename from tests/testcases/test_old_suffix/__init__.py rename to tests/test_main_functionality/__init__.py diff --git a/tests/testcases/test_old_suffix/data/project_stimulus/data/test-project/sub-099/ses-001/beh/sub-666_ses-001_labnotebook.tsv b/tests/test_main_functionality/data/project_other/test-project/data/sub-099/ses-001/beh/sub-666_ses-001_labnotebook.tsv similarity index 100% rename from tests/testcases/test_old_suffix/data/project_stimulus/data/test-project/sub-099/ses-001/beh/sub-666_ses-001_labnotebook.tsv rename to tests/test_main_functionality/data/project_other/test-project/data/sub-099/ses-001/beh/sub-666_ses-001_labnotebook.tsv diff --git a/tests/testcases/test_old_suffix/data/project_stimulus/data/test-project/sub-099/ses-001/beh/sub-666_ses-001_participantform.tsv b/tests/test_main_functionality/data/project_other/test-project/data/sub-099/ses-001/beh/sub-666_ses-001_participantform.tsv similarity index 100% rename from tests/testcases/test_old_suffix/data/project_stimulus/data/test-project/sub-099/ses-001/beh/sub-666_ses-001_participantform.tsv rename to tests/test_main_functionality/data/project_other/test-project/data/sub-099/ses-001/beh/sub-666_ses-001_participantform.tsv diff --git a/tests/testcases/test_old_suffix/data/project_stimulus/data/test-project/sub-099/ses-001/beh/sub_99.edf b/tests/test_main_functionality/data/project_other/test-project/data/sub-099/ses-001/beh/sub_99.edf similarity index 100% rename from tests/testcases/test_old_suffix/data/project_stimulus/data/test-project/sub-099/ses-001/beh/sub_99.edf rename to tests/test_main_functionality/data/project_other/test-project/data/sub-099/ses-001/beh/sub_99.edf diff --git a/tests/testcases/test_old_suffix/data/project_stimulus/data/test-project/sub-099/ses-001/beh/subject-99.csv b/tests/test_main_functionality/data/project_other/test-project/data/sub-099/ses-001/beh/subject-99.csv similarity index 100% rename from tests/testcases/test_old_suffix/data/project_stimulus/data/test-project/sub-099/ses-001/beh/subject-99.csv rename to tests/test_main_functionality/data/project_other/test-project/data/sub-099/ses-001/beh/subject-99.csv diff --git a/tests/test_main_functionality/data/project_other/test-project/data/sub-100/ses-001/beh/sub-666_ses-001_labnotebook.tsv b/tests/test_main_functionality/data/project_other/test-project/data/sub-100/ses-001/beh/sub-666_ses-001_labnotebook.tsv new file mode 100644 index 0000000..c68197a --- /dev/null +++ b/tests/test_main_functionality/data/project_other/test-project/data/sub-100/ses-001/beh/sub-666_ses-001_labnotebook.tsv @@ -0,0 +1,4 @@ +time event what +00:00 cap size selection +00:00 camera working y/n + diff --git a/tests/test_main_functionality/data/project_other/test-project/data/sub-100/ses-001/beh/sub-666_ses-001_participantform.tsv b/tests/test_main_functionality/data/project_other/test-project/data/sub-100/ses-001/beh/sub-666_ses-001_participantform.tsv new file mode 100644 index 0000000..1a6c624 --- /dev/null +++ b/tests/test_main_functionality/data/project_other/test-project/data/sub-100/ses-001/beh/sub-666_ses-001_participantform.tsv @@ -0,0 +1 @@ +id age gender handedness dom_eye no_preex_conditions visual_acuity_test remarks diff --git a/tests/test_main_functionality/data/project_other/test-project/data/sub-100/ses-001/beh/sub_100.edf b/tests/test_main_functionality/data/project_other/test-project/data/sub-100/ses-001/beh/sub_100.edf new file mode 100644 index 0000000..86d8d1e Binary files /dev/null and b/tests/test_main_functionality/data/project_other/test-project/data/sub-100/ses-001/beh/sub_100.edf differ diff --git a/tests/test_main_functionality/data/project_other/test-project/data/sub-100/ses-001/beh/subject-100.csv b/tests/test_main_functionality/data/project_other/test-project/data/sub-100/ses-001/beh/subject-100.csv new file mode 100644 index 0000000..c18df11 --- /dev/null +++ b/tests/test_main_functionality/data/project_other/test-project/data/sub-100/ses-001/beh/subject-100.csv @@ -0,0 +1,4 @@ +"acc","accuracy","average_response_time","avg_rt","background","block_size","canvas_backend","clock_backend","coco_id","color_backend","correct","correct_instructions_sketchpad","correct_keyboard_response","correct_manual_pause_end_kbd","correct_manual_pause_kbd","correct_start_practice_trials_info","correct_welcome","count_PressSpacebar","count_block_sequence","count_break_sequence","count_break_sketchpad","count_end_of_exp","count_end_of_practice","count_endofinstructions","count_endofpractice","count_experiment","count_fixation1_sketchpad","count_fixation_jittered","count_fixation_loop","count_fixation_sequence","count_general_setup","count_getting_started","count_instructions","count_instructions_sketchpad","count_keyboard_response","count_log_all_variables","count_main_loop","count_manual_calibrate","count_manual_pause_end","count_manual_pause_end_kbd","count_manual_pause_kbd","count_manual_pause_start","count_new_1_form_text_display","count_new_1_inline_script","count_new_1_sketchpad","count_new_2_inline_script","count_new_2_sequence","count_new_3_inline_script","count_new_4_inline_script","count_new_5_inline_script","count_new_6_inline_script","count_new_7_inline_script","count_new_advanced_delay","count_new_feedback","count_new_form_text_display","count_new_inline_script","count_new_loop","count_new_pygaze_init","count_new_pygaze_log","count_new_pygaze_start_recording","count_new_pygaze_stop_recording","count_new_reset_feedback","count_new_sequence","count_practiceinstructions","count_practiceloop","count_priliminaryinstructions","count_send_trigger_breakend","count_send_trigger_breakstart","count_send_trigger_end_practice","count_send_trigger_end_stimulus","count_send_trigger_manual_pause_end","count_send_trigger_manual_pause_start","count_send_trigger_start_stimulus","count_setup","count_start_practice_trials_info","count_stimuli","count_stimulus_sequence","count_trial_sequence","count_trigger_setup","count_wait_for_centre_gaze","count_welcome","current_block_no","delay_new_advanced_delay","description","disable_garbage_collection","duration","empty_column","exp_imgdetails_file_name","experiment_file","experiment_path","file_name","file_path_coco_dataset","fixated","font_bold","font_family","font_italic","font_size","font_underline","foreground","form_clicks","fullscreen","gaze_timeout","height","keyboard_backend","license","live_row","live_row_practiceloop","logfile","mouse_backend","n_practicetrials","opensesame_codename","opensesame_version","psychopy_screen","repeat_cycle","response","response_break_sketchpad","response_end_of_exp","response_end_of_practice","response_instructions_sketchpad","response_keyboard_response","response_manual_pause_end_kbd","response_manual_pause_kbd","response_new_1_sketchpad","response_new_feedback","response_start_practice_trials_info","response_time","response_time_break_sketchpad","response_time_end_of_exp","response_time_end_of_practice","response_time_instructions_sketchpad","response_time_keyboard_response","response_time_manual_pause_end_kbd","response_time_manual_pause_kbd","response_time_new_1_sketchpad","response_time_new_feedback","response_time_start_practice_trials_info","response_time_welcome","response_welcome","round_decimals","sampler_backend","sound_buf_size","sound_channels","sound_freq","sound_sample_size","start","subject_nr","subject_parity","time_PressSpacebar","time_block_sequence","time_break_sequence","time_break_sketchpad","time_end_of_exp","time_end_of_practice","time_endofinstructions","time_endofpractice","time_experiment","time_fixation1_sketchpad","time_fixation_jittered","time_fixation_loop","time_fixation_sequence","time_general_setup","time_getting_started","time_instructions","time_instructions_sketchpad","time_keyboard_response","time_log_all_variables","time_main_loop","time_manual_calibrate","time_manual_pause_end","time_manual_pause_end_kbd","time_manual_pause_kbd","time_manual_pause_start","time_new_1_form_text_display","time_new_1_inline_script","time_new_1_sketchpad","time_new_2_inline_script","time_new_2_sequence","time_new_3_inline_script","time_new_4_inline_script","time_new_5_inline_script","time_new_6_inline_script","time_new_7_inline_script","time_new_advanced_delay","time_new_feedback","time_new_form_text_display","time_new_inline_script","time_new_loop","time_new_pygaze_init","time_new_pygaze_log","time_new_pygaze_start_recording","time_new_pygaze_stop_recording","time_new_reset_feedback","time_new_sequence","time_practiceinstructions","time_practiceloop","time_priliminaryinstructions","time_send_trigger_breakend","time_send_trigger_breakstart","time_send_trigger_end_practice","time_send_trigger_end_stimulus","time_send_trigger_manual_pause_end","time_send_trigger_manual_pause_start","time_send_trigger_start_stimulus","time_setup","time_start_practice_trials_info","time_stimuli","time_stimulus_sequence","time_trial_sequence","time_trigger_setup","time_wait_for_centre_gaze","time_welcome","title","tolerance","total_blocks","total_correct","total_response_time","total_responses","total_trials","width" +"undefined","undefined","810","810","#808080","50","psycho","psycho","304187","psycho","undefined","undefined","undefined","NA","NA","undefined","undefined","0","-3","0","0","0","0","NA","NA","0","0","NA","NA","0","0","NA","0","0","0","0","0","1","0","0","0","0","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","0","NA","NA","NA","NA","0","NA","0","0","NA","NA","NA","0","NA","0","0","0","0","0","0","0","0","0","0","0","NA","0","0","0","1","419","The main experiment item","False","650","NA","projects/2024FreeViewingMSCOCO/assets/images/experiment_images_info.csv","free_viewing_experiment.osexp","/home/stimulus/projects/2024FreeViewingMSCOCO/experiment","000000304187_MEG_size.jpg","/scratch/data/coco/coco-2017/train/data/000000304187.jpg","False","False","mono","False","18","no","white","no","yes","5000","1080","psycho","Attribution License","0","0","/home/stimulus/projects/2024FreeViewingMSCOCO/data/sub-099/ses-001/beh/subject-99.csv","psycho","3","Melodramatic Milgram","4.0.13","1","0","space","NA","NA","NA","space","space","NA","NA","NA","NA","space","810.305118560791","NA","NA","NA","588.4740352630615","810.305118560791","NA","NA","NA","NA","398.3440399169922","1945.7039833068848","space","2","psycho","1024","2","48000","-16","experiment","99","odd","14410.46404838562","14407.202959060669","NA","NA","NA","NA","NA","NA","1086.3871574401855","15227.399110794067","NA","NA","14407.315015792847","1647.9620933532715","NA","11160.964012145996","13112.376928329468","14410.552978515625","21306.498050689697","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","15885.131120681763","NA","NA","NA","NA","1086.4861011505127","NA","14100.979089736938","NA","NA","NA","NA","14311.726093292236","NA","NA","NA","NA","21306.37001991272","NA","NA","16304.228067398071","1086.4551067352295","13702.502012252808","16306.323051452637","15885.082006454468","NA","1643.4519290924072","15227.437973022461","11163.213014602661","free_viewing_experiment","44","8","0","810.305118560791","1","400","1920" +"undefined","undefined","671","671","#808080","50","psycho","psycho","303436","psycho","undefined","undefined","undefined","NA","NA","undefined","undefined","1","-2","1","1","0","0","NA","NA","0","1","NA","NA","1","0","NA","0","0","1","1","0","2","1","1","1","1","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","1","NA","NA","NA","NA","0","NA","0","0","NA","NA","NA","0","NA","1","1","0","1","1","1","1","0","0","1","1","NA","0","1","0","1","389","The main experiment item","False","650","NA","projects/2024FreeViewingMSCOCO/assets/images/experiment_images_info.csv","free_viewing_experiment.osexp","/home/stimulus/projects/2024FreeViewingMSCOCO/experiment","000000303436_MEG_size.jpg","/scratch/data/coco/coco-2017/train/data/000000303436.jpg","False","False","mono","False","18","no","white","no","yes","5000","1080","psycho","Attribution-NonCommercial-NoDerivs License","1","1","/home/stimulus/projects/2024FreeViewingMSCOCO/data/sub-099/ses-001/beh/subject-99.csv","psycho","3","Melodramatic Milgram","4.0.13","1","0","space","NA","NA","NA","space","space","NA","NA","NA","NA","space","533.376932144165","NA","NA","NA","588.4740352630615","533.376932144165","NA","NA","NA","NA","398.3440399169922","1945.7039833068848","space","2","psycho","1024","2","48000","-16","experiment","99","odd","21415.446996688843","21412.346124649048","NA","NA","NA","NA","NA","NA","1086.3871574401855","21951.735019683838","NA","NA","21412.39595413208","1647.9620933532715","NA","11160.964012145996","13112.376928329468","21415.497064590454","28000.17809867859","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","22608.845949172974","NA","NA","NA","NA","1086.4861011505127","NA","14100.979089736938","NA","NA","NA","NA","14311.726093292236","NA","NA","NA","NA","28000.051975250244","NA","NA","22997.878074645996","1086.4551067352295","13702.502012252808","22999.948978424072","22608.808040618896","NA","1643.4519290924072","21951.760053634644","11163.213014602661","free_viewing_experiment","44","8","0","1343.682050704956","2","400","1920" +"undefined","undefined","640","640","#808080","50","psycho","psycho","222921","psycho","undefined","undefined","undefined","NA","NA","undefined","undefined","2","-1","2","2","0","0","NA","NA","0","2","NA","NA","2","0","NA","0","0","2","2","0","3","2","2","2","2","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","2","NA","NA","NA","NA","0","NA","0","0","NA","NA","NA","0","NA","2","2","0","2","2","2","2","0","0","2","2","NA","0","2","0","1","375","The main experiment item","False","650","NA","projects/2024FreeViewingMSCOCO/assets/images/experiment_images_info.csv","free_viewing_experiment.osexp","/home/stimulus/projects/2024FreeViewingMSCOCO/experiment","000000222921_MEG_size.jpg","/scratch/data/coco/coco-2017/train/data/000000222921.jpg","False","False","mono","False","18","no","white","no","yes","5000","1080","psycho","Attribution-NonCommercial License","2","2","/home/stimulus/projects/2024FreeViewingMSCOCO/data/sub-099/ses-001/beh/subject-99.csv","psycho","3","Melodramatic Milgram","4.0.13","1","0","space","NA","NA","NA","space","space","NA","NA","NA","NA","space","576.591968536377","NA","NA","NA","588.4740352630615","576.591968536377","NA","NA","NA","NA","398.3440399169922","1945.7039833068848","space","2","psycho","1024","2","48000","-16","experiment","99","odd","28108.245134353638","28105.04913330078","NA","NA","NA","NA","NA","NA","1086.3871574401855","28687.549114227295","NA","NA","28105.098962783813","1647.9620933532715","NA","11160.964012145996","13112.376928329468","28108.291149139404","34722.15914726257","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","29344.93613243103","NA","NA","NA","NA","1086.4861011505127","NA","14100.979089736938","NA","NA","NA","NA","14311.726093292236","NA","NA","NA","NA","34722.04303741455","NA","NA","29719.972133636475","1086.4551067352295","13702.502012252808","29721.93193435669","29344.89893913269","NA","1643.4519290924072","28687.572956085205","11163.213014602661","free_viewing_experiment","44","8","0","1920.274019241333","3","400","1920" diff --git a/tests/test_main_functionality/data/project_other/test-project/experiment/fake_experiment.osexp b/tests/test_main_functionality/data/project_other/test-project/experiment/fake_experiment.osexp new file mode 100644 index 0000000..e69de29 diff --git a/tests/testcases/test_old_suffix/data/projects/test-project/sub-099/ses-001/eeg/sub-099_ses-001_task-freeviewing_run-002_eeg.xdf b/tests/test_main_functionality/data/projects/copy_later/sub-100/ses-001/eeg/sub-100_ses-001_task-freeviewing_run-002_eeg.xdf similarity index 100% rename from tests/testcases/test_old_suffix/data/projects/test-project/sub-099/ses-001/eeg/sub-099_ses-001_task-freeviewing_run-002_eeg.xdf rename to tests/test_main_functionality/data/projects/copy_later/sub-100/ses-001/eeg/sub-100_ses-001_task-freeviewing_run-002_eeg.xdf diff --git a/tests/test_main_functionality/data/projects/test-project/dataset.json b/tests/test_main_functionality/data/projects/test-project/dataset.json new file mode 100644 index 0000000..5e91c22 --- /dev/null +++ b/tests/test_main_functionality/data/projects/test-project/dataset.json @@ -0,0 +1,76 @@ +{ + "datasetVersion": { + "metadataBlocks": { + "citation": { + "fields": [ + { + "typeName": "title", + "multiple": false, + "typeClass": "primitive", + "value": "test-project" + }, + { + "typeName": "author", + "multiple": true, + "typeClass": "compound", + "value": [ + { + "authorName": { + "typeName": "author", + "multiple": false, + "typeClass": "primitive", + "value": "John Doe, Lina Doe" + } + } + ] + }, + { + "typeName": "datasetContact", + "multiple": true, + "typeClass": "compound", + "value": [ + { + "datasetContactName": { + "typeName": "datasetContactName", + "multiple": false, + "typeClass": "primitive", + "value": "John Doe, Lina Doe" + }, + "datasetContactEmail": { + "typeName": "datasetContactEmail", + "multiple": false, + "typeClass": "primitive", + "value": "john@gmail.com" + } + } + ] + }, + { + "typeName": "dsDescription", + "multiple": true, + "typeClass": "compound", + "value": [ + { + "dsDescriptionValue": { + "typeName": "dsDescriptionValue", + "multiple": false, + "typeClass": "primitive", + "value": "This is a test project to set up the pipeline to convert XDF to BIDS." + } + } + ] + }, + { + "typeName": "subject", + "multiple": true, + "typeClass": "controlledVocabulary", + "value": [ + "Medicine, Health and Life Sciences", + "Engineering" + ] + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/testcases/test_old_suffix/data/projects/test-project/sub-099/ses-001/eeg/sub-099_ses-001_task-freeviewing_run-002_eeg_old.xdf b/tests/test_main_functionality/data/projects/test-project/sub-099/ses-001/eeg/sub-099_ses-001_task-freeviewing_run-002_eeg.xdf similarity index 100% rename from tests/testcases/test_old_suffix/data/projects/test-project/sub-099/ses-001/eeg/sub-099_ses-001_task-freeviewing_run-002_eeg_old.xdf rename to tests/test_main_functionality/data/projects/test-project/sub-099/ses-001/eeg/sub-099_ses-001_task-freeviewing_run-002_eeg.xdf diff --git a/tests/test_main_functionality/data/projects/test-project/test-project_config.toml b/tests/test_main_functionality/data/projects/test-project/test-project_config.toml new file mode 100644 index 0000000..0c0d89e --- /dev/null +++ b/tests/test_main_functionality/data/projects/test-project/test-project_config.toml @@ -0,0 +1,22 @@ +[AuthorsInfo] +authors = "John Doe, Lina Doe" +affiliation = "University of Stuttgart, University of Stuttgart" +email = "john@gmail.com" + +[DataverseDataset] +title = "test-project" +datasetDescription = "This is a test project to set up the pipeline to convert XDF to BIDS." +license = "MIT License" +subject = [ "Medicine, Health and Life Sciences", "Engineering",] +pid = "" + +[OtherFilesInfo] +otherFilesUsed = true +expectedOtherFiles = [ ".edf", ".csv", "_labnotebook.tsv", "_participantform.tsv",] + +[FileSelection] +ignoreSubjects = [ "sub-777",] +excludeTasks = [ "sampletask",] + +[BidsConfig] +anonymizationNumber = 123 diff --git a/tests/test_main_functionality/test_main_functionality.py b/tests/test_main_functionality/test_main_functionality.py new file mode 100644 index 0000000..c374d9f --- /dev/null +++ b/tests/test_main_functionality/test_main_functionality.py @@ -0,0 +1,56 @@ +import os +import sys +import pytest +import yaml +import shutil +#import lslautobids +import importlib +#import lslautobids.main +# Compute project root (two levels up from current test.py) +PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +if PROJECT_ROOT not in sys.path: + sys.path.insert(0, PROJECT_ROOT) + + +from path_config import get_root_paths,monkeypatch_paths +#from test_utils.path_config import DummyCLIArgs +# Print test file name for traceability +test_file_name = os.path.basename(__file__) +print(f" Running tests in {test_file_name}") + + + + +@pytest.mark.filterwarnings("ignore::DeprecationWarning") +def test_process_main_functionality(setup_project, monkeypatch): + """ + Expect the main pipeline to raise RuntimeError when duplicate files are found. + """ + project_name = setup_project # fixture via pytest + paths = get_root_paths(__file__) + + monkeypatch_paths(monkeypatch,paths) + + + # Reset sys.argv to something that lslautobids.main.main() expects + # this effectively removes the -c from setup_project + sys.argv = [ + "lslautobids.main", + "-p", project_name, + # other args expected by lslautobids.main.main + ] + + # run once + import lslautobids.main + lslautobids.main.main() + + # add a subject + shutil.copytree(os.path.join(paths["project_root"], "copy_later","sub-100"), os.path.join(paths["project_root"], project_name,"sub-100")) + + lslautobids.main.main() + + # cleanup + shutil.rmtree(os.path.join(paths["project_root"], project_name,"sub-100")) + shutil.rmtree(paths["bids_root"]) + + diff --git a/tests/test_old_suffix/__init__.py b/tests/test_old_suffix/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_old_suffix/data/project_stimulus/data/test-project/sub-099/ses-001/beh/sub-666_ses-001_labnotebook.tsv b/tests/test_old_suffix/data/project_stimulus/data/test-project/sub-099/ses-001/beh/sub-666_ses-001_labnotebook.tsv new file mode 100644 index 0000000..c68197a --- /dev/null +++ b/tests/test_old_suffix/data/project_stimulus/data/test-project/sub-099/ses-001/beh/sub-666_ses-001_labnotebook.tsv @@ -0,0 +1,4 @@ +time event what +00:00 cap size selection +00:00 camera working y/n + diff --git a/tests/test_old_suffix/data/project_stimulus/data/test-project/sub-099/ses-001/beh/sub-666_ses-001_participantform.tsv b/tests/test_old_suffix/data/project_stimulus/data/test-project/sub-099/ses-001/beh/sub-666_ses-001_participantform.tsv new file mode 100644 index 0000000..1a6c624 --- /dev/null +++ b/tests/test_old_suffix/data/project_stimulus/data/test-project/sub-099/ses-001/beh/sub-666_ses-001_participantform.tsv @@ -0,0 +1 @@ +id age gender handedness dom_eye no_preex_conditions visual_acuity_test remarks diff --git a/tests/test_old_suffix/data/project_stimulus/data/test-project/sub-099/ses-001/beh/sub_99.edf b/tests/test_old_suffix/data/project_stimulus/data/test-project/sub-099/ses-001/beh/sub_99.edf new file mode 100644 index 0000000..86d8d1e Binary files /dev/null and b/tests/test_old_suffix/data/project_stimulus/data/test-project/sub-099/ses-001/beh/sub_99.edf differ diff --git a/tests/test_old_suffix/data/project_stimulus/data/test-project/sub-099/ses-001/beh/subject-99.csv b/tests/test_old_suffix/data/project_stimulus/data/test-project/sub-099/ses-001/beh/subject-99.csv new file mode 100644 index 0000000..c18df11 --- /dev/null +++ b/tests/test_old_suffix/data/project_stimulus/data/test-project/sub-099/ses-001/beh/subject-99.csv @@ -0,0 +1,4 @@ +"acc","accuracy","average_response_time","avg_rt","background","block_size","canvas_backend","clock_backend","coco_id","color_backend","correct","correct_instructions_sketchpad","correct_keyboard_response","correct_manual_pause_end_kbd","correct_manual_pause_kbd","correct_start_practice_trials_info","correct_welcome","count_PressSpacebar","count_block_sequence","count_break_sequence","count_break_sketchpad","count_end_of_exp","count_end_of_practice","count_endofinstructions","count_endofpractice","count_experiment","count_fixation1_sketchpad","count_fixation_jittered","count_fixation_loop","count_fixation_sequence","count_general_setup","count_getting_started","count_instructions","count_instructions_sketchpad","count_keyboard_response","count_log_all_variables","count_main_loop","count_manual_calibrate","count_manual_pause_end","count_manual_pause_end_kbd","count_manual_pause_kbd","count_manual_pause_start","count_new_1_form_text_display","count_new_1_inline_script","count_new_1_sketchpad","count_new_2_inline_script","count_new_2_sequence","count_new_3_inline_script","count_new_4_inline_script","count_new_5_inline_script","count_new_6_inline_script","count_new_7_inline_script","count_new_advanced_delay","count_new_feedback","count_new_form_text_display","count_new_inline_script","count_new_loop","count_new_pygaze_init","count_new_pygaze_log","count_new_pygaze_start_recording","count_new_pygaze_stop_recording","count_new_reset_feedback","count_new_sequence","count_practiceinstructions","count_practiceloop","count_priliminaryinstructions","count_send_trigger_breakend","count_send_trigger_breakstart","count_send_trigger_end_practice","count_send_trigger_end_stimulus","count_send_trigger_manual_pause_end","count_send_trigger_manual_pause_start","count_send_trigger_start_stimulus","count_setup","count_start_practice_trials_info","count_stimuli","count_stimulus_sequence","count_trial_sequence","count_trigger_setup","count_wait_for_centre_gaze","count_welcome","current_block_no","delay_new_advanced_delay","description","disable_garbage_collection","duration","empty_column","exp_imgdetails_file_name","experiment_file","experiment_path","file_name","file_path_coco_dataset","fixated","font_bold","font_family","font_italic","font_size","font_underline","foreground","form_clicks","fullscreen","gaze_timeout","height","keyboard_backend","license","live_row","live_row_practiceloop","logfile","mouse_backend","n_practicetrials","opensesame_codename","opensesame_version","psychopy_screen","repeat_cycle","response","response_break_sketchpad","response_end_of_exp","response_end_of_practice","response_instructions_sketchpad","response_keyboard_response","response_manual_pause_end_kbd","response_manual_pause_kbd","response_new_1_sketchpad","response_new_feedback","response_start_practice_trials_info","response_time","response_time_break_sketchpad","response_time_end_of_exp","response_time_end_of_practice","response_time_instructions_sketchpad","response_time_keyboard_response","response_time_manual_pause_end_kbd","response_time_manual_pause_kbd","response_time_new_1_sketchpad","response_time_new_feedback","response_time_start_practice_trials_info","response_time_welcome","response_welcome","round_decimals","sampler_backend","sound_buf_size","sound_channels","sound_freq","sound_sample_size","start","subject_nr","subject_parity","time_PressSpacebar","time_block_sequence","time_break_sequence","time_break_sketchpad","time_end_of_exp","time_end_of_practice","time_endofinstructions","time_endofpractice","time_experiment","time_fixation1_sketchpad","time_fixation_jittered","time_fixation_loop","time_fixation_sequence","time_general_setup","time_getting_started","time_instructions","time_instructions_sketchpad","time_keyboard_response","time_log_all_variables","time_main_loop","time_manual_calibrate","time_manual_pause_end","time_manual_pause_end_kbd","time_manual_pause_kbd","time_manual_pause_start","time_new_1_form_text_display","time_new_1_inline_script","time_new_1_sketchpad","time_new_2_inline_script","time_new_2_sequence","time_new_3_inline_script","time_new_4_inline_script","time_new_5_inline_script","time_new_6_inline_script","time_new_7_inline_script","time_new_advanced_delay","time_new_feedback","time_new_form_text_display","time_new_inline_script","time_new_loop","time_new_pygaze_init","time_new_pygaze_log","time_new_pygaze_start_recording","time_new_pygaze_stop_recording","time_new_reset_feedback","time_new_sequence","time_practiceinstructions","time_practiceloop","time_priliminaryinstructions","time_send_trigger_breakend","time_send_trigger_breakstart","time_send_trigger_end_practice","time_send_trigger_end_stimulus","time_send_trigger_manual_pause_end","time_send_trigger_manual_pause_start","time_send_trigger_start_stimulus","time_setup","time_start_practice_trials_info","time_stimuli","time_stimulus_sequence","time_trial_sequence","time_trigger_setup","time_wait_for_centre_gaze","time_welcome","title","tolerance","total_blocks","total_correct","total_response_time","total_responses","total_trials","width" +"undefined","undefined","810","810","#808080","50","psycho","psycho","304187","psycho","undefined","undefined","undefined","NA","NA","undefined","undefined","0","-3","0","0","0","0","NA","NA","0","0","NA","NA","0","0","NA","0","0","0","0","0","1","0","0","0","0","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","0","NA","NA","NA","NA","0","NA","0","0","NA","NA","NA","0","NA","0","0","0","0","0","0","0","0","0","0","0","NA","0","0","0","1","419","The main experiment item","False","650","NA","projects/2024FreeViewingMSCOCO/assets/images/experiment_images_info.csv","free_viewing_experiment.osexp","/home/stimulus/projects/2024FreeViewingMSCOCO/experiment","000000304187_MEG_size.jpg","/scratch/data/coco/coco-2017/train/data/000000304187.jpg","False","False","mono","False","18","no","white","no","yes","5000","1080","psycho","Attribution License","0","0","/home/stimulus/projects/2024FreeViewingMSCOCO/data/sub-099/ses-001/beh/subject-99.csv","psycho","3","Melodramatic Milgram","4.0.13","1","0","space","NA","NA","NA","space","space","NA","NA","NA","NA","space","810.305118560791","NA","NA","NA","588.4740352630615","810.305118560791","NA","NA","NA","NA","398.3440399169922","1945.7039833068848","space","2","psycho","1024","2","48000","-16","experiment","99","odd","14410.46404838562","14407.202959060669","NA","NA","NA","NA","NA","NA","1086.3871574401855","15227.399110794067","NA","NA","14407.315015792847","1647.9620933532715","NA","11160.964012145996","13112.376928329468","14410.552978515625","21306.498050689697","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","15885.131120681763","NA","NA","NA","NA","1086.4861011505127","NA","14100.979089736938","NA","NA","NA","NA","14311.726093292236","NA","NA","NA","NA","21306.37001991272","NA","NA","16304.228067398071","1086.4551067352295","13702.502012252808","16306.323051452637","15885.082006454468","NA","1643.4519290924072","15227.437973022461","11163.213014602661","free_viewing_experiment","44","8","0","810.305118560791","1","400","1920" +"undefined","undefined","671","671","#808080","50","psycho","psycho","303436","psycho","undefined","undefined","undefined","NA","NA","undefined","undefined","1","-2","1","1","0","0","NA","NA","0","1","NA","NA","1","0","NA","0","0","1","1","0","2","1","1","1","1","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","1","NA","NA","NA","NA","0","NA","0","0","NA","NA","NA","0","NA","1","1","0","1","1","1","1","0","0","1","1","NA","0","1","0","1","389","The main experiment item","False","650","NA","projects/2024FreeViewingMSCOCO/assets/images/experiment_images_info.csv","free_viewing_experiment.osexp","/home/stimulus/projects/2024FreeViewingMSCOCO/experiment","000000303436_MEG_size.jpg","/scratch/data/coco/coco-2017/train/data/000000303436.jpg","False","False","mono","False","18","no","white","no","yes","5000","1080","psycho","Attribution-NonCommercial-NoDerivs License","1","1","/home/stimulus/projects/2024FreeViewingMSCOCO/data/sub-099/ses-001/beh/subject-99.csv","psycho","3","Melodramatic Milgram","4.0.13","1","0","space","NA","NA","NA","space","space","NA","NA","NA","NA","space","533.376932144165","NA","NA","NA","588.4740352630615","533.376932144165","NA","NA","NA","NA","398.3440399169922","1945.7039833068848","space","2","psycho","1024","2","48000","-16","experiment","99","odd","21415.446996688843","21412.346124649048","NA","NA","NA","NA","NA","NA","1086.3871574401855","21951.735019683838","NA","NA","21412.39595413208","1647.9620933532715","NA","11160.964012145996","13112.376928329468","21415.497064590454","28000.17809867859","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","22608.845949172974","NA","NA","NA","NA","1086.4861011505127","NA","14100.979089736938","NA","NA","NA","NA","14311.726093292236","NA","NA","NA","NA","28000.051975250244","NA","NA","22997.878074645996","1086.4551067352295","13702.502012252808","22999.948978424072","22608.808040618896","NA","1643.4519290924072","21951.760053634644","11163.213014602661","free_viewing_experiment","44","8","0","1343.682050704956","2","400","1920" +"undefined","undefined","640","640","#808080","50","psycho","psycho","222921","psycho","undefined","undefined","undefined","NA","NA","undefined","undefined","2","-1","2","2","0","0","NA","NA","0","2","NA","NA","2","0","NA","0","0","2","2","0","3","2","2","2","2","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","2","NA","NA","NA","NA","0","NA","0","0","NA","NA","NA","0","NA","2","2","0","2","2","2","2","0","0","2","2","NA","0","2","0","1","375","The main experiment item","False","650","NA","projects/2024FreeViewingMSCOCO/assets/images/experiment_images_info.csv","free_viewing_experiment.osexp","/home/stimulus/projects/2024FreeViewingMSCOCO/experiment","000000222921_MEG_size.jpg","/scratch/data/coco/coco-2017/train/data/000000222921.jpg","False","False","mono","False","18","no","white","no","yes","5000","1080","psycho","Attribution-NonCommercial License","2","2","/home/stimulus/projects/2024FreeViewingMSCOCO/data/sub-099/ses-001/beh/subject-99.csv","psycho","3","Melodramatic Milgram","4.0.13","1","0","space","NA","NA","NA","space","space","NA","NA","NA","NA","space","576.591968536377","NA","NA","NA","588.4740352630615","576.591968536377","NA","NA","NA","NA","398.3440399169922","1945.7039833068848","space","2","psycho","1024","2","48000","-16","experiment","99","odd","28108.245134353638","28105.04913330078","NA","NA","NA","NA","NA","NA","1086.3871574401855","28687.549114227295","NA","NA","28105.098962783813","1647.9620933532715","NA","11160.964012145996","13112.376928329468","28108.291149139404","34722.15914726257","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","29344.93613243103","NA","NA","NA","NA","1086.4861011505127","NA","14100.979089736938","NA","NA","NA","NA","14311.726093292236","NA","NA","NA","NA","34722.04303741455","NA","NA","29719.972133636475","1086.4551067352295","13702.502012252808","29721.93193435669","29344.89893913269","NA","1643.4519290924072","28687.572956085205","11163.213014602661","free_viewing_experiment","44","8","0","1920.274019241333","3","400","1920" diff --git a/tests/test_old_suffix/data/projects/test-project/sub-099/ses-001/eeg/sub-099_ses-001_task-freeviewing_run-002_eeg.xdf b/tests/test_old_suffix/data/projects/test-project/sub-099/ses-001/eeg/sub-099_ses-001_task-freeviewing_run-002_eeg.xdf new file mode 100644 index 0000000..6239d63 Binary files /dev/null and b/tests/test_old_suffix/data/projects/test-project/sub-099/ses-001/eeg/sub-099_ses-001_task-freeviewing_run-002_eeg.xdf differ diff --git a/tests/test_old_suffix/data/projects/test-project/sub-099/ses-001/eeg/sub-099_ses-001_task-freeviewing_run-002_eeg_old.xdf b/tests/test_old_suffix/data/projects/test-project/sub-099/ses-001/eeg/sub-099_ses-001_task-freeviewing_run-002_eeg_old.xdf new file mode 100644 index 0000000..6239d63 Binary files /dev/null and b/tests/test_old_suffix/data/projects/test-project/sub-099/ses-001/eeg/sub-099_ses-001_task-freeviewing_run-002_eeg_old.xdf differ diff --git a/tests/test_old_suffix/data/projects/test-project/test-project_config.toml b/tests/test_old_suffix/data/projects/test-project/test-project_config.toml new file mode 100644 index 0000000..0c0d89e --- /dev/null +++ b/tests/test_old_suffix/data/projects/test-project/test-project_config.toml @@ -0,0 +1,22 @@ +[AuthorsInfo] +authors = "John Doe, Lina Doe" +affiliation = "University of Stuttgart, University of Stuttgart" +email = "john@gmail.com" + +[DataverseDataset] +title = "test-project" +datasetDescription = "This is a test project to set up the pipeline to convert XDF to BIDS." +license = "MIT License" +subject = [ "Medicine, Health and Life Sciences", "Engineering",] +pid = "" + +[OtherFilesInfo] +otherFilesUsed = true +expectedOtherFiles = [ ".edf", ".csv", "_labnotebook.tsv", "_participantform.tsv",] + +[FileSelection] +ignoreSubjects = [ "sub-777",] +excludeTasks = [ "sampletask",] + +[BidsConfig] +anonymizationNumber = 123 diff --git a/tests/test_old_suffix/test_old_suffix.py b/tests/test_old_suffix/test_old_suffix.py new file mode 100644 index 0000000..d1a44bd --- /dev/null +++ b/tests/test_old_suffix/test_old_suffix.py @@ -0,0 +1,47 @@ +import os +import sys +import pytest +import yaml + + +import importlib +# Compute project root (two levels up from current test.py) +PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +if PROJECT_ROOT not in sys.path: + sys.path.insert(0, PROJECT_ROOT) + +from path_config import get_root_paths,monkeypatch_paths +#from test_utils.path_config import DummyCLIArgs + +# Print test file name for traceability +test_file_name = os.path.basename(__file__) +print(f" Running tests in {test_file_name}") + + + +@pytest.mark.filterwarnings("ignore::DeprecationWarning") +def test_process_new_files_with_old_suffix(setup_project, monkeypatch): + """ + Expect the main pipeline to raise RuntimeError when duplicate files are found. + """ + project_name = setup_project + paths = get_root_paths(__file__) + + monkeypatch_paths(monkeypatch,paths) + + # Reset sys.argv to something that lslautobids.main.main() expects + sys.argv = [ + "lslautobids.main", + "-p", project_name, + # other args expected by lslautobids.main.main + ] + + + import lslautobids.main + + # Import and run main pipeline, expect a RuntimeError + with pytest.raises(SystemExit, match="Duplicate file detected. Please check the file manually."): + lslautobids.main.main() + + + diff --git a/tests/test_utils/path_config.py b/tests/test_utils/path_config.py deleted file mode 100644 index 1499565..0000000 --- a/tests/test_utils/path_config.py +++ /dev/null @@ -1,20 +0,0 @@ -import os - -def get_root_paths(test_file: str): - """ - Given a test file (__file__), return relevant test root paths. - """ - # Use the test_file argument, not __file__ from path_config.py - test_folder = os.path.basename(os.path.dirname(test_file)) - - # Go up to the test folder's path and into its `data/` directory - base_dir = os.path.abspath(os.path.join(os.path.dirname(test_file), "data")) - - print(f'The base dir in the get_roots_path function is "{base_dir}"') - return { - "project_root": os.path.join(base_dir, "projects"), - "bids_root": os.path.join(base_dir, "bids"), - "project_other_root": os.path.join(base_dir, "project_other"), - } - -