code: def test_migrate_config(td):
      profile = pjoin(td, "profile")
      jpy = pjoin(td, "jupyter_config")
      ensure_dir_exists(profile)
  
      env = {
          "profile": profile,
          "jupyter_config": jpy,
      }
      cfg_py = pjoin(profile, "ipython_test_config.py")
      touch(cfg_py, "c.Klass.trait = 5\n")
      empty_cfg_py = pjoin(profile, "ipython_empty_config.py")
      touch(empty_cfg_py, "# c.Klass.trait = 5\n")
  
      assert not migrate_config("empty", env)
      assert not os.path.exists(jpy)
  
      with patch.dict(
          migrate_mod.config_substitutions,
          {
              re.compile(r"\bKlass\b"): "Replaced",
          },
      ):
          assert migrate_config("test", env)
  
      assert os.path.isdir(jpy)
      assert sorted(os.listdir(jpy)) == [
          "jupyter_test_config.py",
      ]
  
      with open(
          pjoin(jpy, "jupyter_test_config.py"), encoding="utf-8"
      ) as f:
          text = f.read()
      assert text == "c.Replaced.trait = 5\n"
  
imports: from __future__ import annotations
  import os
  import re
  import shutil
  from tempfile import mkdtemp
  from unittest.mock import patch
  import pytest
  from jupyter_core import migrate
  from jupyter_core.application import JupyterApp
  from jupyter_core.migrate import migrate, migrate_config, migrate_dir, migrate_file, migrate_one, migrate_static_custom
  from jupyter_core.utils import ensure_dir_exists
label_desc: Use image node_id 8 for calling a global function with example usage: test_migrate_config(td) without return types