99import sys
1010from pathlib import Path
1111from types import ModuleType , SimpleNamespace
12- from typing import Any , TYPE_CHECKING , cast
12+ from typing import TYPE_CHECKING , Any , cast
1313from unittest .mock import Mock , patch
1414
1515import pytest
@@ -667,6 +667,86 @@ def test_check_azure_providers_json_error() -> None:
667667 assert 'Log in' in fix or 'login' in fix .lower ()
668668
669669
670+ # ============================================================
671+ # Tests for check_git_notebook_filter
672+ # ============================================================
673+
674+
675+ def _git_config_side_effect (clean : str | Exception , smudge : str | Exception ):
676+ """Build a subprocess.run side_effect that answers git config --get calls."""
677+
678+ def _run (cmd , ** kwargs ):
679+ key = cmd [- 1 ]
680+ value = clean if key == 'filter.notebook-metadata.clean' else smudge
681+ if isinstance (value , Exception ):
682+ raise value
683+ return Mock (stdout = f'{ value } \n ' , returncode = 0 )
684+
685+ return _run
686+
687+
688+ def test_check_git_notebook_filter_git_missing () -> None :
689+ """Git notebook filter check should fail when git is not on PATH."""
690+ with patch ('shutil.which' , return_value = None ):
691+ ok , fix = vls .check_git_notebook_filter ()
692+ assert ok is False
693+ assert 'Install Git' in fix
694+
695+
696+ def test_check_git_notebook_filter_configured () -> None :
697+ """Git notebook filter check should pass when clean and smudge match expected values."""
698+ side_effect = _git_config_side_effect (
699+ clean = 'python setup/normalize_notebook_metadata.py' ,
700+ smudge = 'cat' ,
701+ )
702+ with patch ('shutil.which' , return_value = '/usr/bin/git' ):
703+ with patch ('subprocess.run' , side_effect = side_effect ):
704+ ok , fix = vls .check_git_notebook_filter ()
705+ assert ok is True
706+ assert not fix
707+
708+
709+ def test_check_git_notebook_filter_not_configured () -> None :
710+ """Git notebook filter check should fail when git config key is unset (exit 1)."""
711+ with patch ('shutil.which' , return_value = '/usr/bin/git' ):
712+ with patch ('subprocess.run' , side_effect = subprocess .CalledProcessError (1 , 'git' )):
713+ ok , fix = vls .check_git_notebook_filter ()
714+ assert ok is False
715+ assert 'Complete environment setup' in fix
716+
717+
718+ def test_check_git_notebook_filter_wrong_clean_value () -> None :
719+ """Git notebook filter check should fail when clean filter points to something unexpected."""
720+ side_effect = _git_config_side_effect (clean = 'nbstripout' , smudge = 'cat' )
721+ with patch ('shutil.which' , return_value = '/usr/bin/git' ):
722+ with patch ('subprocess.run' , side_effect = side_effect ):
723+ ok , fix = vls .check_git_notebook_filter ()
724+ assert ok is False
725+ assert 'nbstripout' in fix
726+
727+
728+ def test_check_git_notebook_filter_wrong_smudge_value () -> None :
729+ """Git notebook filter check should fail when smudge filter is not 'cat'."""
730+ side_effect = _git_config_side_effect (
731+ clean = 'python setup/normalize_notebook_metadata.py' ,
732+ smudge = 'python something_else.py' ,
733+ )
734+ with patch ('shutil.which' , return_value = '/usr/bin/git' ):
735+ with patch ('subprocess.run' , side_effect = side_effect ):
736+ ok , fix = vls .check_git_notebook_filter ()
737+ assert ok is False
738+ assert 'something_else' in fix
739+
740+
741+ def test_check_git_notebook_filter_git_exec_missing () -> None :
742+ """Git notebook filter check should fail gracefully when git disappears between which() and run()."""
743+ with patch ('shutil.which' , return_value = '/usr/bin/git' ):
744+ with patch ('subprocess.run' , side_effect = FileNotFoundError ()):
745+ ok , fix = vls .check_git_notebook_filter ()
746+ assert ok is False
747+ assert 'Install Git' in fix
748+
749+
670750# ============================================================
671751# Tests for main function
672752# ============================================================
@@ -686,6 +766,7 @@ def _mock_all_checks(monkeypatch: pytest.MonkeyPatch, **overrides: tuple[bool, s
686766 'check_azure_providers' : (True , '' ),
687767 'check_jupyter_kernel' : (True , '' ),
688768 'check_vscode_settings' : (True , '' ),
769+ 'check_git_notebook_filter' : (True , '' ),
689770 }
690771 defaults .update (overrides )
691772 for check_name , result in defaults .items ():
0 commit comments