From 8751231103eda0ed466217a4d3b4dc2493e591b6 Mon Sep 17 00:00:00 2001
From: Mashiro <57566630+HAOCHENYE@users.noreply.github.com>
Date: Thu, 17 Feb 2022 17:46:06 +0800
Subject: [PATCH] add config test (#10)

* add config test

* Fix typo

Co-authored-by: Zaida Zhou <58739961+zhouzaida@users.noreply.github.com>

* Update tests/config/test_config.py

Co-authored-by: Zaida Zhou <58739961+zhouzaida@users.noreply.github.com>

* Reconstruct config test

* Fix import logic and error test

* Fix path error

* Restructuring Config

* simplify test logic

simplify test logic

* rename test_config file

* add test complex dump and pretty text

* adjust test sequence according to comment

adjust test sequence according to comment

* add comment and test for simple.config.py

* add config test data

* add init

* remove __pycache__

* fix as comment

* add syntax test case

* remove tmp path and modify comment

* add test for setattr

Co-authored-by: Zaida Zhou <58739961+zhouzaida@users.noreply.github.com>
---
 .gitignore                                    |   2 -
 .pre-commit-config.yaml                       |   1 +
 tests/data/config/json_config/base3.json      |   3 +
 .../config/json_config/simple.config.json     |   8 +
 .../config/json_config/simple_config.json     |   8 +
 tests/data/config/json_config/test_base.json  |  13 +
 .../test_base_variables_nested.json           |  26 +
 .../json_config/test_predefined_var.json      |   3 +
 .../config/json_config/test_reserved_key.json |   3 +
 tests/data/config/py_config/base.py           |   5 +
 tests/data/config/py_config/base1.py          |   2 +
 tests/data/config/py_config/base4.py          |   4 +
 tests/data/config/py_config/config.py         |   5 +
 tests/data/config/py_config/simple.config.py  |   5 +
 tests/data/config/py_config/simple_config.py  |   5 +
 .../config/py_config/test_base_variables.py   |  11 +
 .../py_config/test_base_variables_nested.py   |  13 +
 .../config/py_config/test_code_in_config.py   |   5 +
 .../config/py_config/test_custom_import.py    |   3 +
 .../py_config/test_custom_import_module.py    |   4 +
 .../py_config/test_dump_pickle_support.py     |  17 +
 .../config/py_config/test_merge_delete.py     |   4 +
 .../py_config/test_merge_from_base_error.py   |   3 +
 .../py_config/test_merge_from_base_single.py  |   6 +
 .../config/py_config/test_merge_from_dict.py  |   2 +
 .../test_merge_from_multiple_bases.py         |   9 +
 .../test_merge_from_multiple_error.py         |   7 +
 .../test_merge_intermediate_variable_base.py  |   8 +
 .../test_merge_intermediate_variable_child.py |   4 +
 .../py_config/test_merge_recursive_bases.py   |   3 +
 .../test_pre_substitute_base_vars.py          |  11 +
 .../config/py_config/test_predefined_var.py   |   4 +
 .../config/py_config/test_reserved_key.py     |   2 +
 tests/data/config/yaml_config/base2.yaml      |   1 +
 .../config/yaml_config/simple.config.yaml     |   4 +
 .../config/yaml_config/simple_config.yaml     |   4 +
 tests/data/config/yaml_config/test_base.yaml  |   6 +
 .../test_base_variables_nested.yaml           |  15 +
 .../yaml_config/test_predefined_var.yaml      |   1 +
 .../config/yaml_config/test_reserved_key.yaml |   1 +
 tests/test_config/test_config.py              | 627 ++++++++++++++++++
 41 files changed, 866 insertions(+), 2 deletions(-)
 create mode 100644 tests/data/config/json_config/base3.json
 create mode 100644 tests/data/config/json_config/simple.config.json
 create mode 100644 tests/data/config/json_config/simple_config.json
 create mode 100644 tests/data/config/json_config/test_base.json
 create mode 100644 tests/data/config/json_config/test_base_variables_nested.json
 create mode 100644 tests/data/config/json_config/test_predefined_var.json
 create mode 100644 tests/data/config/json_config/test_reserved_key.json
 create mode 100644 tests/data/config/py_config/base.py
 create mode 100644 tests/data/config/py_config/base1.py
 create mode 100644 tests/data/config/py_config/base4.py
 create mode 100644 tests/data/config/py_config/config.py
 create mode 100644 tests/data/config/py_config/simple.config.py
 create mode 100644 tests/data/config/py_config/simple_config.py
 create mode 100644 tests/data/config/py_config/test_base_variables.py
 create mode 100644 tests/data/config/py_config/test_base_variables_nested.py
 create mode 100644 tests/data/config/py_config/test_code_in_config.py
 create mode 100644 tests/data/config/py_config/test_custom_import.py
 create mode 100644 tests/data/config/py_config/test_custom_import_module.py
 create mode 100644 tests/data/config/py_config/test_dump_pickle_support.py
 create mode 100644 tests/data/config/py_config/test_merge_delete.py
 create mode 100644 tests/data/config/py_config/test_merge_from_base_error.py
 create mode 100644 tests/data/config/py_config/test_merge_from_base_single.py
 create mode 100644 tests/data/config/py_config/test_merge_from_dict.py
 create mode 100644 tests/data/config/py_config/test_merge_from_multiple_bases.py
 create mode 100644 tests/data/config/py_config/test_merge_from_multiple_error.py
 create mode 100644 tests/data/config/py_config/test_merge_intermediate_variable_base.py
 create mode 100644 tests/data/config/py_config/test_merge_intermediate_variable_child.py
 create mode 100644 tests/data/config/py_config/test_merge_recursive_bases.py
 create mode 100644 tests/data/config/py_config/test_pre_substitute_base_vars.py
 create mode 100644 tests/data/config/py_config/test_predefined_var.py
 create mode 100644 tests/data/config/py_config/test_reserved_key.py
 create mode 100644 tests/data/config/yaml_config/base2.yaml
 create mode 100644 tests/data/config/yaml_config/simple.config.yaml
 create mode 100644 tests/data/config/yaml_config/simple_config.yaml
 create mode 100644 tests/data/config/yaml_config/test_base.yaml
 create mode 100644 tests/data/config/yaml_config/test_base_variables_nested.yaml
 create mode 100644 tests/data/config/yaml_config/test_predefined_var.yaml
 create mode 100644 tests/data/config/yaml_config/test_reserved_key.yaml
 create mode 100644 tests/test_config/test_config.py

diff --git a/.gitignore b/.gitignore
index 8f6fd08e..00379477 100644
--- a/.gitignore
+++ b/.gitignore
@@ -105,8 +105,6 @@ venv.bak/
 # mypy
 .mypy_cache/
 
-data/
-data
 .vscode
 .idea
 .DS_Store
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index fb7df7ad..98d142c3 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,3 +1,4 @@
+exclude: ^tests/data/
 repos:
   - repo: https://gitlab.com/pycqa/flake8.git
     rev: 3.8.3
diff --git a/tests/data/config/json_config/base3.json b/tests/data/config/json_config/base3.json
new file mode 100644
index 00000000..3251c5d6
--- /dev/null
+++ b/tests/data/config/json_config/base3.json
@@ -0,0 +1,3 @@
+{
+  "item3": true
+}
diff --git a/tests/data/config/json_config/simple.config.json b/tests/data/config/json_config/simple.config.json
new file mode 100644
index 00000000..cc317436
--- /dev/null
+++ b/tests/data/config/json_config/simple.config.json
@@ -0,0 +1,8 @@
+{
+    "item1": [1, 2],
+    "item2": {
+        "a": 0
+    },
+    "item3": true,
+    "item4": "test"
+}
diff --git a/tests/data/config/json_config/simple_config.json b/tests/data/config/json_config/simple_config.json
new file mode 100644
index 00000000..cc317436
--- /dev/null
+++ b/tests/data/config/json_config/simple_config.json
@@ -0,0 +1,8 @@
+{
+    "item1": [1, 2],
+    "item2": {
+        "a": 0
+    },
+    "item3": true,
+    "item4": "test"
+}
diff --git a/tests/data/config/json_config/test_base.json b/tests/data/config/json_config/test_base.json
new file mode 100644
index 00000000..dd2917b9
--- /dev/null
+++ b/tests/data/config/json_config/test_base.json
@@ -0,0 +1,13 @@
+{
+    "_base_": [
+        "../py_config/base1.py",
+        "../yaml_config/base2.yaml",
+        "./base3.json",
+        "../py_config/base4.py"
+    ],
+    "item3": false,
+    "item4": "test",
+    "item8": "{{fileBasename}}",
+    "item9": {{ _base_.item2 }},
+    "item10": {{ _base_.item7.b.c }}
+}
diff --git a/tests/data/config/json_config/test_base_variables_nested.json b/tests/data/config/json_config/test_base_variables_nested.json
new file mode 100644
index 00000000..af13a7eb
--- /dev/null
+++ b/tests/data/config/json_config/test_base_variables_nested.json
@@ -0,0 +1,26 @@
+{
+    "_base_": [
+        "../py_config/test_base_variables.py"
+    ],
+    "base": "_base_.item8",
+    "item11": {{ _base_.item8 }},
+    "item12": {{ _base_.item9 }},
+    "item13": {{ _base_.item10 }},
+    "item14": {{ _base_.item1 }},
+    "item15": {
+        "a": {
+            "b": {{ _base_.item2 }}
+        },
+        "b": [
+            {{ _base_.item3 }}
+        ],
+        "c": [{{ _base_.item4 }}],
+        "d": [[
+            {
+                "e": {{ _base_.item5.a }}
+            }
+        ],
+        {{ _base_.item6 }}],
+        "e": {{ _base_.item1 }}
+    }
+}
diff --git a/tests/data/config/json_config/test_predefined_var.json b/tests/data/config/json_config/test_predefined_var.json
new file mode 100644
index 00000000..84c5e3ed
--- /dev/null
+++ b/tests/data/config/json_config/test_predefined_var.json
@@ -0,0 +1,3 @@
+{
+    "item1": "{{ fileDirname }}"
+}
diff --git a/tests/data/config/json_config/test_reserved_key.json b/tests/data/config/json_config/test_reserved_key.json
new file mode 100644
index 00000000..599d20a9
--- /dev/null
+++ b/tests/data/config/json_config/test_reserved_key.json
@@ -0,0 +1,3 @@
+{
+  "filename": "reserved.py"
+}
diff --git a/tests/data/config/py_config/base.py b/tests/data/config/py_config/base.py
new file mode 100644
index 00000000..2364e1d1
--- /dev/null
+++ b/tests/data/config/py_config/base.py
@@ -0,0 +1,5 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+item1 = [1, 2]
+item2 = {'a': 0}
+item3 = True
+item4 = 'test'
diff --git a/tests/data/config/py_config/base1.py b/tests/data/config/py_config/base1.py
new file mode 100644
index 00000000..13db1375
--- /dev/null
+++ b/tests/data/config/py_config/base1.py
@@ -0,0 +1,2 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+item1 = [1, 2]
diff --git a/tests/data/config/py_config/base4.py b/tests/data/config/py_config/base4.py
new file mode 100644
index 00000000..cb7b4365
--- /dev/null
+++ b/tests/data/config/py_config/base4.py
@@ -0,0 +1,4 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+item5 = dict(a=0, b=1)
+item6 = [dict(a=0), dict(b=1)]
+item7 = dict(a=[0, 1, 2], b=dict(c=[3.1, 4.2, 5.3]))
diff --git a/tests/data/config/py_config/config.py b/tests/data/config/py_config/config.py
new file mode 100644
index 00000000..65c03bf8
--- /dev/null
+++ b/tests/data/config/py_config/config.py
@@ -0,0 +1,5 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+test_int = 1
+test_list = [1, 2, 3]
+# include type, optimizer can be initiated by build_from_cfg
+optimizer = dict(type='SGD', lr=0.1, momentum=0.9, weight_decay=0.0001)
diff --git a/tests/data/config/py_config/simple.config.py b/tests/data/config/py_config/simple.config.py
new file mode 100644
index 00000000..2364e1d1
--- /dev/null
+++ b/tests/data/config/py_config/simple.config.py
@@ -0,0 +1,5 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+item1 = [1, 2]
+item2 = {'a': 0}
+item3 = True
+item4 = 'test'
diff --git a/tests/data/config/py_config/simple_config.py b/tests/data/config/py_config/simple_config.py
new file mode 100644
index 00000000..2364e1d1
--- /dev/null
+++ b/tests/data/config/py_config/simple_config.py
@@ -0,0 +1,5 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+item1 = [1, 2]
+item2 = {'a': 0}
+item3 = True
+item4 = 'test'
diff --git a/tests/data/config/py_config/test_base_variables.py b/tests/data/config/py_config/test_base_variables.py
new file mode 100644
index 00000000..4d20d7f0
--- /dev/null
+++ b/tests/data/config/py_config/test_base_variables.py
@@ -0,0 +1,11 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+_base_ = [
+    './base1.py', '../yaml_config/base2.yaml', '../json_config/base3.json',
+    './base4.py'
+]
+
+item3 = False
+item4 = 'test'
+item8 = '{{fileBasename}}'
+item9 = {{_base_.item2}}
+item10 = {{_base_.item7.b.c}}
diff --git a/tests/data/config/py_config/test_base_variables_nested.py b/tests/data/config/py_config/test_base_variables_nested.py
new file mode 100644
index 00000000..ea9a6004
--- /dev/null
+++ b/tests/data/config/py_config/test_base_variables_nested.py
@@ -0,0 +1,13 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+_base_ = ['./test_base_variables.py']
+base = '_base_.item8'
+item11 = {{_base_.item8}}
+item12 = {{_base_.item9}}
+item13 = {{_base_.item10}}
+item14 = {{_base_.item1}}
+item15 = dict(
+    a=dict(b={{_base_.item2}}),
+    b=[{{_base_.item3}}],
+    c=[{{_base_.item4}}],
+    d=[[dict(e={{_base_.item5.a}})], {{_base_.item6}}],
+    e={{_base_.item1}})
diff --git a/tests/data/config/py_config/test_code_in_config.py b/tests/data/config/py_config/test_code_in_config.py
new file mode 100644
index 00000000..cd59844b
--- /dev/null
+++ b/tests/data/config/py_config/test_code_in_config.py
@@ -0,0 +1,5 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+from mmcv import Config  # isort:skip
+
+cfg = Config.fromfile('tests/data/config/py_config/simple_config.py')
+item5 = cfg.item1[0] + cfg.item2.a
diff --git a/tests/data/config/py_config/test_custom_import.py b/tests/data/config/py_config/test_custom_import.py
new file mode 100644
index 00000000..d485a190
--- /dev/null
+++ b/tests/data/config/py_config/test_custom_import.py
@@ -0,0 +1,3 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+custom_imports = dict(
+    imports=['test_custom_import_module'], allow_failed_imports=False)
diff --git a/tests/data/config/py_config/test_custom_import_module.py b/tests/data/config/py_config/test_custom_import_module.py
new file mode 100644
index 00000000..853b31ae
--- /dev/null
+++ b/tests/data/config/py_config/test_custom_import_module.py
@@ -0,0 +1,4 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+import os
+
+os.environ['TEST_VALUE'] = 'test'
diff --git a/tests/data/config/py_config/test_dump_pickle_support.py b/tests/data/config/py_config/test_dump_pickle_support.py
new file mode 100644
index 00000000..fa7aae26
--- /dev/null
+++ b/tests/data/config/py_config/test_dump_pickle_support.py
@@ -0,0 +1,17 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+test_item1 = [1, 2]
+bool_item2 = True
+str_item3 = 'test'
+dict_item4 = dict(
+    a={
+        'c/d': 'path/d',
+        'f': 's3//f',
+        6: '2333',
+        '2333': 'number'
+    },
+    b={'8': 543},
+    c={9: 678},
+    d={'a': 0},
+    f=dict(a='69'))
+dict_item5 = {'x/x': {'a.0': 233}}
+dict_list_item6 = {'x/x': [{'a.0': 1., 'b.0': 2.}, {'c/3': 3.}]}
diff --git a/tests/data/config/py_config/test_merge_delete.py b/tests/data/config/py_config/test_merge_delete.py
new file mode 100644
index 00000000..f8a1eaf6
--- /dev/null
+++ b/tests/data/config/py_config/test_merge_delete.py
@@ -0,0 +1,4 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+_base_ = './base.py'
+item1 = {'a': 0, '_delete_': True}
+item2 = {'b': 0}
diff --git a/tests/data/config/py_config/test_merge_from_base_error.py b/tests/data/config/py_config/test_merge_from_base_error.py
new file mode 100644
index 00000000..1340e4bd
--- /dev/null
+++ b/tests/data/config/py_config/test_merge_from_base_error.py
@@ -0,0 +1,3 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+_base_ = './base.py'
+item3 = {'a': 1}
diff --git a/tests/data/config/py_config/test_merge_from_base_single.py b/tests/data/config/py_config/test_merge_from_base_single.py
new file mode 100644
index 00000000..19edcf82
--- /dev/null
+++ b/tests/data/config/py_config/test_merge_from_base_single.py
@@ -0,0 +1,6 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+_base_ = './base.py'
+item1 = [2, 3]
+item2 = {'a': 1}
+item3 = False
+item4 = 'test_base'
diff --git a/tests/data/config/py_config/test_merge_from_dict.py b/tests/data/config/py_config/test_merge_from_dict.py
new file mode 100644
index 00000000..cca07539
--- /dev/null
+++ b/tests/data/config/py_config/test_merge_from_dict.py
@@ -0,0 +1,2 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+item = [{'a': 0}, {'b': 0, 'c': 0}]
diff --git a/tests/data/config/py_config/test_merge_from_multiple_bases.py b/tests/data/config/py_config/test_merge_from_multiple_bases.py
new file mode 100644
index 00000000..da575c39
--- /dev/null
+++ b/tests/data/config/py_config/test_merge_from_multiple_bases.py
@@ -0,0 +1,9 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+_base_ = [
+    './base1.py', '../yaml_config/base2.yaml', '../json_config/base3.json',
+    './base4.py'
+]
+item3 = False
+item4 = 'test'
+item_bool = True
+item_float = 1.0
diff --git a/tests/data/config/py_config/test_merge_from_multiple_error.py b/tests/data/config/py_config/test_merge_from_multiple_error.py
new file mode 100644
index 00000000..b38596d9
--- /dev/null
+++ b/tests/data/config/py_config/test_merge_from_multiple_error.py
@@ -0,0 +1,7 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+_base_ = [
+    './base1.py', '../yaml_config/base2.yaml', '../json_config/base3.json',
+    'simple_config.py'
+]
+item3 = False
+item4 = 'test'
diff --git a/tests/data/config/py_config/test_merge_intermediate_variable_base.py b/tests/data/config/py_config/test_merge_intermediate_variable_base.py
new file mode 100644
index 00000000..f31a46a1
--- /dev/null
+++ b/tests/data/config/py_config/test_merge_intermediate_variable_base.py
@@ -0,0 +1,8 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+item1 = [1, 2]
+item2 = {'a': 0}
+item3 = True
+item4 = 'test'
+item_cfg = {'b': 1}
+item5 = {'cfg': item_cfg}
+item6 = {'cfg': item_cfg}
diff --git a/tests/data/config/py_config/test_merge_intermediate_variable_child.py b/tests/data/config/py_config/test_merge_intermediate_variable_child.py
new file mode 100644
index 00000000..17325b13
--- /dev/null
+++ b/tests/data/config/py_config/test_merge_intermediate_variable_child.py
@@ -0,0 +1,4 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+_base_ = './test_merge_intermediate_variable_base.py'
+item_cfg = {'b': 2}
+item6 = {'cfg': item_cfg}
diff --git a/tests/data/config/py_config/test_merge_recursive_bases.py b/tests/data/config/py_config/test_merge_recursive_bases.py
new file mode 100644
index 00000000..6d2218ba
--- /dev/null
+++ b/tests/data/config/py_config/test_merge_recursive_bases.py
@@ -0,0 +1,3 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+_base_ = './test_merge_from_base_single.py'
+item4 = 'test_recursive_bases'
diff --git a/tests/data/config/py_config/test_pre_substitute_base_vars.py b/tests/data/config/py_config/test_pre_substitute_base_vars.py
new file mode 100644
index 00000000..72d67ab4
--- /dev/null
+++ b/tests/data/config/py_config/test_pre_substitute_base_vars.py
@@ -0,0 +1,11 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+_base_ = ['./test_base_variables_nested.py']
+item21 = {{_base_.item11}}
+item22 = item21
+item23 = {{_base_.item10}}
+item24 = item23
+item25 = dict(
+    a=dict(b=item24),
+    b=[item24],
+    c=[[dict(e=item22)], {{_base_.item6}}],
+    e=item21)
diff --git a/tests/data/config/py_config/test_predefined_var.py b/tests/data/config/py_config/test_predefined_var.py
new file mode 100644
index 00000000..82594590
--- /dev/null
+++ b/tests/data/config/py_config/test_predefined_var.py
@@ -0,0 +1,4 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+item1 = '{{fileBasename}}'
+item2 = '{{ fileDirname}}'
+item3 = 'abc_{{ fileBasenameNoExtension }}'
diff --git a/tests/data/config/py_config/test_reserved_key.py b/tests/data/config/py_config/test_reserved_key.py
new file mode 100644
index 00000000..34d4ebe2
--- /dev/null
+++ b/tests/data/config/py_config/test_reserved_key.py
@@ -0,0 +1,2 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+filename = 'reserved.py'
diff --git a/tests/data/config/yaml_config/base2.yaml b/tests/data/config/yaml_config/base2.yaml
new file mode 100644
index 00000000..b73902b3
--- /dev/null
+++ b/tests/data/config/yaml_config/base2.yaml
@@ -0,0 +1 @@
+item2: {'a': 0}
diff --git a/tests/data/config/yaml_config/simple.config.yaml b/tests/data/config/yaml_config/simple.config.yaml
new file mode 100644
index 00000000..5365b714
--- /dev/null
+++ b/tests/data/config/yaml_config/simple.config.yaml
@@ -0,0 +1,4 @@
+item1: [1, 2]
+item2: {'a': 0}
+item3: True
+item4: 'test'
diff --git a/tests/data/config/yaml_config/simple_config.yaml b/tests/data/config/yaml_config/simple_config.yaml
new file mode 100644
index 00000000..5365b714
--- /dev/null
+++ b/tests/data/config/yaml_config/simple_config.yaml
@@ -0,0 +1,4 @@
+item1: [1, 2]
+item2: {'a': 0}
+item3: True
+item4: 'test'
diff --git a/tests/data/config/yaml_config/test_base.yaml b/tests/data/config/yaml_config/test_base.yaml
new file mode 100644
index 00000000..db16138e
--- /dev/null
+++ b/tests/data/config/yaml_config/test_base.yaml
@@ -0,0 +1,6 @@
+_base_ : ['../py_config/base1.py', './base2.yaml', '../json_config/base3.json', '../py_config/base4.py']
+item3 : False
+item4 : 'test'
+item8 : '{{fileBasename}}'
+item9 : {{ _base_.item2 }}
+item10 : {{ _base_.item7.b.c }}
diff --git a/tests/data/config/yaml_config/test_base_variables_nested.yaml b/tests/data/config/yaml_config/test_base_variables_nested.yaml
new file mode 100644
index 00000000..8b3431de
--- /dev/null
+++ b/tests/data/config/yaml_config/test_base_variables_nested.yaml
@@ -0,0 +1,15 @@
+_base_: ["../py_config/test_base_variables.py"]
+base: "_base_.item8"
+item11: {{ _base_.item8 }}
+item12: {{ _base_.item9 }}
+item13: {{ _base_.item10 }}
+item14: {{ _base_.item1 }}
+item15:
+    a:
+        b: {{ _base_.item2 }}
+    b: [{{ _base_.item3 }}]
+    c: [{{ _base_.item4 }}]
+    d:
+        - [e: {{ _base_.item5.a }}]
+        - {{ _base_.item6 }}
+    e: {{ _base_.item1 }}
diff --git a/tests/data/config/yaml_config/test_predefined_var.yaml b/tests/data/config/yaml_config/test_predefined_var.yaml
new file mode 100644
index 00000000..3b3e46e8
--- /dev/null
+++ b/tests/data/config/yaml_config/test_predefined_var.yaml
@@ -0,0 +1 @@
+item1: '{{ fileDirname }}'
diff --git a/tests/data/config/yaml_config/test_reserved_key.yaml b/tests/data/config/yaml_config/test_reserved_key.yaml
new file mode 100644
index 00000000..456aceb1
--- /dev/null
+++ b/tests/data/config/yaml_config/test_reserved_key.yaml
@@ -0,0 +1 @@
+filename: reserved.py
diff --git a/tests/test_config/test_config.py b/tests/test_config/test_config.py
new file mode 100644
index 00000000..9f3d121c
--- /dev/null
+++ b/tests/test_config/test_config.py
@@ -0,0 +1,627 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+import argparse
+import os
+import os.path as osp
+import platform
+import sys
+from importlib import import_module
+from pathlib import Path
+
+import pytest
+
+from mmengine import Config, ConfigDict, DictAction
+from mmengine.fileio import dump, load
+
+
+class TestConfig:
+    data_path = osp.join(osp.dirname(osp.dirname(__file__)), 'data/')
+
+    @pytest.mark.parametrize('file_format', ['py', 'json', 'yaml'])
+    def test_init(self, file_format):
+        # test init Config by __init__
+        cfg = Config()
+        assert cfg.filename is None
+        assert cfg.text == ''
+        assert len(cfg) == 0
+        assert cfg._cfg_dict == {}
+
+        # test `cfg_dict` parameter
+        # `cfg_dict` is either dict or None
+        with pytest.raises(TypeError, match='cfg_dict must be a dict'):
+            Config([0, 1])
+
+        # test `filename` parameter
+        cfg_dict = dict(
+            item1=[1, 2], item2=dict(a=0), item3=True, item4='test')
+        cfg_file = osp.join(
+            self.data_path,
+            f'config/{file_format}_config/simple_config.{file_format}')
+        cfg = Config(cfg_dict, filename=cfg_file)
+        assert isinstance(cfg, Config)
+        assert cfg.filename == cfg_file
+        assert cfg.text == open(cfg_file, 'r').read()
+
+        cfg_file = osp.join(
+            self.data_path,
+            f'config/{file_format}_config/test_reserved_key.{file_format}')
+        # reserved keys cannot be set in config
+        with pytest.raises(
+                KeyError, match='filename is reserved for config '
+                'file'):
+            Config.fromfile(cfg_file)
+
+    def test_fromfile(self):
+        # test whether import `custom_imports` from cfg_file.
+        cfg_file = osp.join(self.data_path, 'config',
+                            'py_config/test_custom_import.py')
+        sys.path.append(osp.join(self.data_path, 'config/py_config'))
+        cfg = Config.fromfile(cfg_file, import_custom_modules=True)
+        assert isinstance(cfg, Config)
+        # If import successfully, os.environ[''TEST_VALUE''] will be
+        # set to 'test'
+        assert os.environ.pop('TEST_VALUE') == 'test'
+        Config.fromfile(cfg_file, import_custom_modules=False)
+        assert 'TEST_VALUE' not in os.environ
+
+    @pytest.mark.parametrize('file_format', ['py', 'json', 'yaml'])
+    def test_fromstring(self, file_format):
+        filename = f'{file_format}_config/simple_config.{file_format}'
+        cfg_file = osp.join(self.data_path, 'config', filename)
+        file_format = osp.splitext(filename)[-1]
+        in_cfg = Config.fromfile(cfg_file)
+
+        cfg_str = open(cfg_file, 'r').read()
+        out_cfg = Config.fromstring(cfg_str, file_format)
+        assert in_cfg._cfg_dict == out_cfg._cfg_dict
+
+        # test pretty_text only supports py file format
+        # in_cfg.pretty_text is .py format, cannot be parsed to .json
+        if file_format != '.py':
+            with pytest.raises(Exception):
+                Config.fromstring(in_cfg.pretty_text, file_format)
+
+        # error format
+        with pytest.raises(IOError):
+            Config.fromstring(cfg_str, '.xml')
+
+    def test_magic_methods(self):
+        cfg_dict = dict(
+            item1=[1, 2], item2=dict(a=0), item3=True, item4='test')
+        filename = 'py_config/simple_config.py'
+        cfg_file = osp.join(self.data_path, 'config', filename)
+        cfg = Config.fromfile(cfg_file)
+        # len(cfg)
+        assert len(cfg) == 4
+        # cfg.keys()
+        assert set(cfg.keys()) == set(cfg_dict.keys())
+        assert set(cfg._cfg_dict.keys()) == set(cfg_dict.keys())
+        # cfg.values()
+        for value in cfg.values():
+            assert value in cfg_dict.values()
+        # cfg.items()
+        for name, value in cfg.items():
+            assert name in cfg_dict
+            assert value in cfg_dict.values()
+        # cfg.field
+        assert cfg.item1 == cfg_dict['item1']
+        assert cfg.item2 == cfg_dict['item2']
+        assert cfg.item2.a == 0
+        assert cfg.item3 == cfg_dict['item3']
+        assert cfg.item4 == cfg_dict['item4']
+        # accessing keys that do not exist will cause error
+        with pytest.raises(AttributeError):
+            cfg.not_exist
+        # field in cfg, cfg[field], cfg.get()
+        for name in ['item1', 'item2', 'item3', 'item4']:
+            assert name in cfg
+            assert cfg[name] == cfg_dict[name]
+            assert cfg.get(name) == cfg_dict[name]
+            assert cfg.get('not_exist') is None
+            assert cfg.get('not_exist', 0) == 0
+            # accessing keys that do not exist will cause error
+            with pytest.raises(KeyError):
+                cfg['not_exist']
+        assert 'item1' in cfg
+        assert 'not_exist' not in cfg
+        # cfg.update()
+        cfg.update(dict(item1=0))
+        assert cfg.item1 == 0
+        cfg.update(dict(item2=dict(a=1)))
+        assert cfg.item2.a == 1
+        # test __setattr__
+        cfg = Config()
+        cfg.item1 = [1, 2]
+        cfg.item2 = {'a': 0}
+        cfg['item5'] = {'a': {'b': None}}
+        assert cfg._cfg_dict['item1'] == [1, 2]
+        assert cfg.item1 == [1, 2]
+        assert cfg._cfg_dict['item2'] == {'a': 0}
+        assert cfg.item2.a == 0
+        assert cfg._cfg_dict['item5'] == {'a': {'b': None}}
+        assert cfg.item5.a.b is None
+
+    def test_merge_from_dict(self):
+        cfg_file = osp.join(self.data_path,
+                            'config/py_config/simple_config.py')
+        cfg = Config.fromfile(cfg_file)
+        input_options = {'item2.a': 1, 'item2.b': 0.1, 'item3': False}
+        cfg.merge_from_dict(input_options)
+        assert cfg.item2 == dict(a=1, b=0.1)
+        assert cfg.item3 is False
+
+        cfg_file = osp.join(self.data_path,
+                            'config/py_config/test_merge_from_dict.py')
+        cfg = Config.fromfile(cfg_file)
+
+        # Allow list keys
+        input_options = {'item.0.a': 1, 'item.1.b': 1}
+        cfg.merge_from_dict(input_options, allow_list_keys=True)
+        assert cfg.item == [{'a': 1}, {'b': 1, 'c': 0}]
+
+        # allow_list_keys is False
+        input_options = {'item.0.a': 1, 'item.1.b': 1}
+        with pytest.raises(TypeError):
+            cfg.merge_from_dict(input_options, allow_list_keys=False)
+
+        # Overflowed index number
+        input_options = {'item.2.a': 1}
+        with pytest.raises(KeyError):
+            cfg.merge_from_dict(input_options, allow_list_keys=True)
+
+    def test_auto_argparser(self):
+        tmp = sys.argv[1]
+        sys.argv[1] = osp.join(
+            self.data_path,
+            'config/py_config/test_merge_from_multiple_bases.py')
+        parser, cfg = Config.auto_argparser()
+        args = parser.parse_args()
+        assert args.config == sys.argv[1]
+        for key in cfg._cfg_dict.keys():
+            if not isinstance(cfg[key], ConfigDict):
+                assert getattr(args, key) is None
+        # TODO currently do not support nested keys, bool args will be
+        #  overwritten by int
+        sys.argv[1] = tmp
+
+    @pytest.mark.parametrize('file_path', [
+        'config/py_config/simple_config.py',
+        'config/py_config/test_merge_from_multiple_bases.py'
+    ])
+    def test_dump(self, file_path, tmp_path):
+        cfg_file = osp.join(self.data_path, file_path)
+        cfg = Config.fromfile(cfg_file)
+        dump_py = tmp_path / 'simple_config.py'
+        dump_json = tmp_path / 'simple_config.json'
+        dump_yaml = tmp_path / 'simple_config.yaml'
+
+        cfg.dump(dump_py)
+        cfg.dump(dump_json)
+        cfg.dump(dump_yaml)
+
+        assert cfg.dump() == cfg.pretty_text
+
+        assert open(dump_py, 'r').read() == cfg.pretty_text
+        assert open(dump_json, 'r').read() == cfg.pretty_text
+        assert open(dump_yaml, 'r').read() == cfg.pretty_text
+
+        # test pickle
+        cfg_file = osp.join(self.data_path,
+                            'config/py_config/test_dump_pickle_support.py')
+        cfg = Config.fromfile(cfg_file)
+
+        text_cfg_filename = tmp_path / '_text_config.py'
+        cfg.dump(text_cfg_filename)
+        text_cfg = Config.fromfile(text_cfg_filename)
+
+        assert text_cfg._cfg_dict == cfg._cfg_dict
+
+        cfg_file = osp.join(self.data_path,
+                            'config/py_config/test_dump_pickle_support.py')
+        cfg = Config.fromfile(cfg_file)
+
+        pkl_cfg_filename = tmp_path / '_pickle.pkl'
+        dump(cfg, pkl_cfg_filename)
+        pkl_cfg = load(pkl_cfg_filename)
+
+        assert pkl_cfg._cfg_dict == cfg._cfg_dict
+
+    def test_pretty_text(self, tmp_path):
+        cfg_file = osp.join(
+            self.data_path,
+            'config/py_config/test_merge_from_multiple_bases.py')
+        cfg = Config.fromfile(cfg_file)
+        text_cfg_filename = tmp_path / '_text_config.py'
+        with open(text_cfg_filename, 'w') as f:
+            f.write(cfg.pretty_text)
+        text_cfg = Config.fromfile(text_cfg_filename)
+        assert text_cfg._cfg_dict == cfg._cfg_dict
+
+    def test_repr(self, tmp_path):
+        cfg_file = osp.join(self.data_path,
+                            'config/py_config/simple_config.py')
+        cfg = Config.fromfile(cfg_file)
+        tmp_txt = tmp_path / 'tmp.txt'
+        with open(tmp_txt, 'w') as f:
+            print(cfg, file=f)
+        with open(tmp_txt, 'r') as f:
+            assert f.read().strip() == f'Config (path: {cfg.filename}): ' \
+                               f'{cfg._cfg_dict.__repr__()}'
+
+    def test_dict_action(self):
+        parser = argparse.ArgumentParser(description='Train a detector')
+        parser.add_argument(
+            '--options', nargs='+', action=DictAction, help='custom options')
+        # Nested brackets
+        args = parser.parse_args(
+            ['--options', 'item2.a=a,b', 'item2.b=[(a,b), [1,2], false]'])
+        out_dict = {
+            'item2.a': ['a', 'b'],
+            'item2.b': [('a', 'b'), [1, 2], False]
+        }
+        assert args.options == out_dict
+        # Single Nested brackets
+        args = parser.parse_args(['--options', 'item2.a=[[1]]'])
+        out_dict = {'item2.a': [[1]]}
+        assert args.options == out_dict
+        # Imbalance bracket will cause error
+        with pytest.raises(AssertionError):
+            parser.parse_args(['--options', 'item2.a=[(a,b), [1,2], false'])
+        # Normal values
+        args = parser.parse_args([
+            '--options', 'item2.a=1', 'item2.b=0.1', 'item2.c=x', 'item3=false'
+        ])
+        out_dict = {
+            'item2.a': 1,
+            'item2.b': 0.1,
+            'item2.c': 'x',
+            'item3': False
+        }
+        assert args.options == out_dict
+        cfg_file = osp.join(self.data_path,
+                            'config/py_config/simple_config.py')
+        cfg = Config.fromfile(cfg_file)
+        cfg.merge_from_dict(args.options)
+        assert cfg.item2 == dict(a=1, b=0.1, c='x')
+        assert cfg.item3 is False
+
+    def test_validate_py_syntax(self, tmp_path):
+        tmp_cfg = tmp_path / 'tmp_config.py'
+        with open(tmp_cfg, 'w') as f:
+            f.write('dict(a=1,b=2.c=3)')
+        # Incorrect point in dict will cause error
+        with pytest.raises(SyntaxError):
+            Config._validate_py_syntax(tmp_cfg)
+        with open(tmp_cfg, 'w') as f:
+            f.write('[dict(a=1, b=2, c=(1, 2)]')
+        # Imbalance bracket will cause error
+        with pytest.raises(SyntaxError):
+            Config._validate_py_syntax(tmp_cfg)
+        with open(tmp_cfg, 'w') as f:
+            f.write('dict(a=1,b=2\nc=3)')
+        # Incorrect feed line in dict will cause error
+        with pytest.raises(SyntaxError):
+            Config._validate_py_syntax(tmp_cfg)
+
+    def test_substitute_predefined_vars(self, tmp_path):
+        cfg_text = 'a={{fileDirname}}\n' \
+                   'b={{fileBasename}}\n' \
+                   'c={{fileBasenameNoExtension}}\n' \
+                   'd={{fileExtname}}\n'
+
+        cfg = tmp_path / 'tmp_cfg1.py'
+        substituted_cfg = tmp_path / 'tmp_cfg2.py'
+
+        file_dirname = osp.dirname(cfg)
+        file_basename = osp.basename(cfg)
+        file_basename_no_extension = osp.splitext(file_basename)[0]
+        file_extname = osp.splitext(cfg)[1]
+
+        expected_text = f'a={file_dirname}\n' \
+                        f'b={file_basename}\n' \
+                        f'c={file_basename_no_extension}\n' \
+                        f'd={file_extname}\n'
+        expected_text = expected_text.replace('\\', '/')
+        with open(cfg, 'w') as f:
+            f.write(cfg_text)
+        Config._substitute_predefined_vars(cfg, substituted_cfg)
+
+        with open(substituted_cfg, 'r') as f:
+            assert f.read() == expected_text
+
+    def test_pre_substitute_base_vars(self, tmp_path):
+        cfg_path = osp.join(self.data_path, 'config',
+                            'py_config/test_pre_substitute_base_vars.py')
+        tmp_cfg = tmp_path / 'tmp_cfg.py'
+        base_var_dict = Config._pre_substitute_base_vars(cfg_path, tmp_cfg)
+        assert 'item6' in base_var_dict.values()
+        assert 'item10' in base_var_dict.values()
+        assert 'item11' in base_var_dict.values()
+        sys.path.append(str(tmp_path))
+        cfg_module_dict = import_module(tmp_cfg.name.strip('.py')).__dict__
+        assert cfg_module_dict['item22'].startswith('_item11')
+        assert cfg_module_dict['item23'].startswith('_item10')
+        assert cfg_module_dict['item25']['c'][1].startswith('_item6')
+        sys.path.pop()
+
+        cfg_path = osp.join(self.data_path, 'config',
+                            'json_config/test_base.json')
+        tmp_cfg = tmp_path / 'tmp_cfg.json'
+        Config._pre_substitute_base_vars(cfg_path, tmp_cfg)
+        cfg_module_dict = load(tmp_cfg)
+        assert cfg_module_dict['item9'].startswith('_item2')
+        assert cfg_module_dict['item10'].startswith('_item7')
+
+        cfg_path = osp.join(self.data_path, 'config',
+                            'yaml_config/test_base.yaml')
+        tmp_cfg = tmp_path / 'tmp_cfg.yaml'
+        Config._pre_substitute_base_vars(cfg_path, tmp_cfg)
+        cfg_module_dict = load(tmp_cfg)
+        assert cfg_module_dict['item9'].startswith('_item2')
+        assert cfg_module_dict['item10'].startswith('_item7')
+
+    def test_substitute_base_vars(self):
+        cfg = dict(
+            item4='_item1.12345',
+            item5=dict(item3='1', item2='_item2_.fswf'),
+            item0=('_item0_.12ed21wq', 1))
+        cfg_base = dict(item1=0, item2=[1, 2, 3], item0=(1, 2, 3))
+        base_var_dict = {
+            '_item1.12345': 'item1',
+            '_item2_.fswf': 'item2',
+            '_item0_.12ed21wq': 'item0'
+        }
+        cfg = Config._substitute_base_vars(cfg, base_var_dict, cfg_base)
+        assert cfg['item4'] == cfg_base['item1']
+        assert cfg['item5']['item2'] == cfg_base['item2']
+
+    def test_file2dict(self, tmp_path):
+
+        # test error format config
+        tmp_cfg = tmp_path / 'tmp_cfg.xml'
+        tmp_cfg.write_text('exist')
+        # invalid config format
+        with pytest.raises(IOError):
+            Config.fromfile(tmp_cfg)
+        # invalid config file path
+        with pytest.raises(FileNotFoundError):
+            Config.fromfile('no_such_file.py')
+
+        self._simple_load()
+        self._predefined_vars()
+        self._base_variables()
+        self._merge_from_base()
+        self._code_in_config()
+        self._merge_from_multiple_bases()
+        self._merge_delete()
+        self._merge_intermediate_variable()
+        self._merge_recursive_bases()
+
+    def _simple_load(self):
+        # test load simple config
+        for file_format in ['py', 'json', 'yaml']:
+            for name in ['simple.config', 'simple_config']:
+                filename = f'{file_format}_config/{name}.{file_format}'
+
+                cfg_file = osp.join(self.data_path, 'config', filename)
+                cfg_dict, cfg_text = Config._file2dict(cfg_file)
+                assert isinstance(cfg_text, str)
+                assert isinstance(cfg_dict, dict)
+
+    def _get_file_path(self, file_path):
+        if platform.system() == 'Windows':
+            return file_path.replace('\\', '/')
+        else:
+            return file_path
+
+    def _predefined_vars(self):
+        # test parse predefined_var in config
+        cfg_file = osp.join(self.data_path,
+                            'config/py_config/test_predefined_var.py')
+        path = osp.join(self.data_path, 'config/py_config')
+
+        path = Path(path).as_posix()
+        cfg_dict_dst = dict(
+            item1='test_predefined_var.py',
+            item2=path,
+            item3='abc_test_predefined_var')
+
+        assert Config._file2dict(cfg_file)[0]['item1'] == cfg_dict_dst['item1']
+        assert Config._file2dict(cfg_file)[0]['item2'] == cfg_dict_dst['item2']
+        assert Config._file2dict(cfg_file)[0]['item3'] == cfg_dict_dst['item3']
+
+        # test `use_predefined_variable=False`
+        cfg_dict_ori = dict(
+            item1='{{fileBasename}}',
+            item2='{{ fileDirname}}',
+            item3='abc_{{ fileBasenameNoExtension }}')
+
+        assert Config._file2dict(cfg_file,
+                                 False)[0]['item1'] == cfg_dict_ori['item1']
+        assert Config._file2dict(cfg_file,
+                                 False)[0]['item2'] == cfg_dict_ori['item2']
+        assert Config._file2dict(cfg_file,
+                                 False)[0]['item3'] == cfg_dict_ori['item3']
+
+        # test test_predefined_var.yaml
+        cfg_file = osp.join(self.data_path,
+                            'config/yaml_config/test_predefined_var.yaml')
+
+        # test `use_predefined_variable=False`
+        assert Config._file2dict(cfg_file,
+                                 False)[0]['item1'] == '{{ fileDirname }}'
+        assert Config._file2dict(cfg_file)[0]['item1'] == self._get_file_path(
+            osp.dirname(cfg_file))
+
+        # test test_predefined_var.json
+        cfg_file = osp.join(self.data_path,
+                            'config/json_config/test_predefined_var.json')
+
+        assert Config.fromfile(cfg_file, False)['item1'] == '{{ fileDirname }}'
+        assert Config.fromfile(cfg_file)['item1'] == self._get_file_path(
+            osp.dirname(cfg_file))
+
+    def _merge_from_base(self):
+        cfg_file = osp.join(self.data_path,
+                            'config/py_config/test_merge_from_base_single.py')
+        cfg_dict = Config._file2dict(cfg_file)[0]
+
+        assert cfg_dict['item1'] == [2, 3]
+        assert cfg_dict['item2']['a'] == 1
+        assert cfg_dict['item3'] is False
+        assert cfg_dict['item4'] == 'test_base'
+        # item3 is a dict in the child config but a boolean in base config
+        with pytest.raises(TypeError):
+            Config.fromfile(
+                osp.join(self.data_path,
+                         'config/py_config/test_merge_from_base_error.py'))
+
+    def _merge_from_multiple_bases(self):
+        cfg_file = osp.join(
+            self.data_path,
+            'config/py_config/test_merge_from_multiple_bases.py')
+        cfg_dict = Config._file2dict(cfg_file)[0]
+
+        # cfg.fcfg_dictd
+        assert cfg_dict['item1'] == [1, 2]
+        assert cfg_dict['item2']['a'] == 0
+        assert cfg_dict['item3'] is False
+        assert cfg_dict['item4'] == 'test'
+        assert cfg_dict['item5'] == dict(a=0, b=1)
+        assert cfg_dict['item6'] == [dict(a=0), dict(b=1)]
+        assert cfg_dict['item7'] == dict(
+            a=[0, 1, 2], b=dict(c=[3.1, 4.2, 5.3]))
+        # Redefine key
+        with pytest.raises(KeyError):
+            Config.fromfile(
+                osp.join(self.data_path,
+                         'config/py_config/test_merge_from_multiple_error.py'))
+
+    def _base_variables(self):
+        for file in [
+                'py_config/test_base_variables.py',
+                'json_config/test_base.json', 'yaml_config/test_base.yaml'
+        ]:
+            cfg_file = osp.join(self.data_path, 'config', file)
+            cfg_dict = Config._file2dict(cfg_file)[0]
+
+            assert cfg_dict['item1'] == [1, 2]
+            assert cfg_dict['item2']['a'] == 0
+            assert cfg_dict['item3'] is False
+            assert cfg_dict['item4'] == 'test'
+            assert cfg_dict['item5'] == dict(a=0, b=1)
+            assert cfg_dict['item6'] == [dict(a=0), dict(b=1)]
+            assert cfg_dict['item7'] == dict(
+                a=[0, 1, 2], b=dict(c=[3.1, 4.2, 5.3]))
+            assert cfg_dict['item8'] == file.split('/')[-1]
+            assert cfg_dict['item9'] == dict(a=0)
+            assert cfg_dict['item10'] == [3.1, 4.2, 5.3]
+
+        # test nested base
+        for file in [
+                'py_config/test_base_variables_nested.py',
+                'json_config/test_base_variables_nested.json',
+                'yaml_config/test_base_variables_nested.yaml'
+        ]:
+            cfg_file = osp.join(self.data_path, 'config', file)
+            cfg_dict = Config._file2dict(cfg_file)[0]
+
+            assert cfg_dict['base'] == '_base_.item8'
+            assert cfg_dict['item1'] == [1, 2]
+            assert cfg_dict['item2']['a'] == 0
+            assert cfg_dict['item3'] is False
+            assert cfg_dict['item4'] == 'test'
+            assert cfg_dict['item5'] == dict(a=0, b=1)
+            assert cfg_dict['item6'] == [dict(a=0), dict(b=1)]
+            assert cfg_dict['item7'] == dict(
+                a=[0, 1, 2], b=dict(c=[3.1, 4.2, 5.3]))
+            assert cfg_dict['item8'] == 'test_base_variables.py'
+            assert cfg_dict['item9'] == dict(a=0)
+            assert cfg_dict['item10'] == [3.1, 4.2, 5.3]
+            assert cfg_dict['item11'] == 'test_base_variables.py'
+            assert cfg_dict['item12'] == dict(a=0)
+            assert cfg_dict['item13'] == [3.1, 4.2, 5.3]
+            assert cfg_dict['item14'] == [1, 2]
+            assert cfg_dict['item15'] == dict(
+                a=dict(b=dict(a=0)),
+                b=[False],
+                c=['test'],
+                d=[[{
+                    'e': 0
+                }], [{
+                    'a': 0
+                }, {
+                    'b': 1
+                }]],
+                e=[1, 2])
+
+        # test reference assignment for py
+        cfg_file = osp.join(
+            self.data_path,
+            'config/py_config/test_pre_substitute_base_vars.py')
+        cfg_dict = Config._file2dict(cfg_file)[0]
+
+        assert cfg_dict['item21'] == 'test_base_variables.py'
+        assert cfg_dict['item22'] == 'test_base_variables.py'
+        assert cfg_dict['item23'] == [3.1, 4.2, 5.3]
+        assert cfg_dict['item24'] == [3.1, 4.2, 5.3]
+        assert cfg_dict['item25'] == dict(
+            a=dict(b=[3.1, 4.2, 5.3]),
+            b=[[3.1, 4.2, 5.3]],
+            c=[[{
+                'e': 'test_base_variables.py'
+            }], [{
+                'a': 0
+            }, {
+                'b': 1
+            }]],
+            e='test_base_variables.py')
+
+    def _merge_recursive_bases(self):
+        cfg_file = osp.join(self.data_path,
+                            'config/py_config/test_merge_recursive_bases.py')
+        cfg_dict = Config._file2dict(cfg_file)[0]
+
+        assert cfg_dict['item1'] == [2, 3]
+        assert cfg_dict['item2']['a'] == 1
+        assert cfg_dict['item3'] is False
+        assert cfg_dict['item4'] == 'test_recursive_bases'
+
+    def _merge_delete(self):
+        cfg_file = osp.join(self.data_path,
+                            'config/py_config/test_merge_delete.py')
+        cfg_dict = Config._file2dict(cfg_file)[0]
+        # cfg.field
+        assert cfg_dict['item1'] == dict(a=0)
+        assert cfg_dict['item2'] == dict(a=0, b=0)
+        assert cfg_dict['item3'] is True
+        assert cfg_dict['item4'] == 'test'
+        assert '_delete_' not in cfg_dict['item2']
+
+        assert type(cfg_dict['item1']) == ConfigDict
+        assert type(cfg_dict['item2']) == dict
+
+    def _merge_intermediate_variable(self):
+
+        cfg_file = osp.join(
+            self.data_path,
+            'config/py_config/test_merge_intermediate_variable_child.py')
+        cfg_dict = Config._file2dict(cfg_file)[0]
+        # cfg.field
+        assert cfg_dict['item1'] == [1, 2]
+        assert cfg_dict['item2'] == dict(a=0)
+        assert cfg_dict['item3'] is True
+        assert cfg_dict['item4'] == 'test'
+        assert cfg_dict['item_cfg'] == dict(b=2)
+        assert cfg_dict['item5'] == dict(cfg=dict(b=1))
+        assert cfg_dict['item6'] == dict(cfg=dict(b=2))
+
+    def _code_in_config(self):
+        cfg_file = osp.join(self.data_path,
+                            'config/py_config/test_code_in_config.py')
+        cfg = Config.fromfile(cfg_file)
+        # cfg.field
+        assert cfg.cfg.item1 == [1, 2]
+        assert cfg.cfg.item2 == dict(a=0)
+        assert cfg.cfg.item3 is True
+        assert cfg.cfg.item4 == 'test'
+        assert cfg.item5 == 1
-- 
GitLab