From: Julian Braha <julianbraha@gmail.com>
To: nathan@kernel.org, nsc@kernel.org
Cc: ojeda@kernel.org, akpm@linux-foundation.org,
jani.nikula@linux.intel.com, gary@garyguo.net,
gregkh@linuxfoundation.org, arnd@arndb.de, ljs@kernel.org,
andrew.jones@linux.dev, masahiroy@kernel.org, corbet@lwn.net,
qingfang.deng@linux.dev, demiobenour@gmail.com, ej@inai.de,
linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org,
linux-doc@vger.kernel.org, linux-kbuild@vger.kernel.org,
Julian Braha <julianbraha@gmail.com>
Subject: [PATCH v4 3/5] kconfirm: add tests
Date: Mon, 27 Jul 2026 01:16:21 +0100 [thread overview]
Message-ID: <20260727001623.2794156-4-julianbraha@gmail.com> (raw)
In-Reply-To: <20260727001623.2794156-1-julianbraha@gmail.com>
Add tests for kconfirm using pytest, as Kconfig does. The tests cover all
of kconfirm’s checks, and any additional, future checks need to add tests
as well.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Julian Braha <julianbraha@gmail.com>
---
.../kconfig/kconfirm/tests/arch/arm/Kconfig | 9 +
.../kconfirm/tests/arch/powerpc/Kconfig | 4 +
.../kconfig/kconfirm/tests/arch/riscv/Kconfig | 9 +
.../kconfig/kconfirm/tests/arch/sh/Kconfig | 4 +
.../kconfirm/tests/arch/testarch/Kconfig | 4 +
.../kconfig/kconfirm/tests/arch/um/Kconfig | 4 +
.../kconfig/kconfirm/tests/arch/x86/Kconfig | 4 +
.../kconfirm/tests/architecture.Kconfig | 4 +
.../tests/architecture_common.Kconfig | 19 +
.../kconfirm/tests/conditional_prompt.Kconfig | 17 +
scripts/kconfig/kconfirm/tests/conftest.py | 93 +++++
...nt_condition_negative_expression_1.Kconfig | 13 +
...nt_condition_negative_expression_2.Kconfig | 13 +
...nstant_condition_negative_symbol_1.Kconfig | 13 +
...nstant_condition_negative_symbol_2.Kconfig | 13 +
.../kconfig/kconfirm/tests/dead_link.Kconfig | 12 +
.../tests/default_categorization.Kconfig | 20 +
scripts/kconfig/kconfirm/tests/pytest.ini | 2 +
scripts/kconfig/kconfirm/tests/ranges.Kconfig | 39 ++
.../kconfirm/tests/select_imply.Kconfig | 28 ++
.../kconfig/kconfirm/tests/test_kconfirm.py | 358 ++++++++++++++++++
21 files changed, 682 insertions(+)
create mode 100644 scripts/kconfig/kconfirm/tests/arch/arm/Kconfig
create mode 100644 scripts/kconfig/kconfirm/tests/arch/powerpc/Kconfig
create mode 100644 scripts/kconfig/kconfirm/tests/arch/riscv/Kconfig
create mode 100644 scripts/kconfig/kconfirm/tests/arch/sh/Kconfig
create mode 100644 scripts/kconfig/kconfirm/tests/arch/testarch/Kconfig
create mode 100644 scripts/kconfig/kconfirm/tests/arch/um/Kconfig
create mode 100644 scripts/kconfig/kconfirm/tests/arch/x86/Kconfig
create mode 100644 scripts/kconfig/kconfirm/tests/architecture.Kconfig
create mode 100644 scripts/kconfig/kconfirm/tests/architecture_common.Kconfig
create mode 100644 scripts/kconfig/kconfirm/tests/conditional_prompt.Kconfig
create mode 100644 scripts/kconfig/kconfirm/tests/conftest.py
create mode 100644 scripts/kconfig/kconfirm/tests/constant_condition/default_constant_condition_negative_expression_1.Kconfig
create mode 100644 scripts/kconfig/kconfirm/tests/constant_condition/default_constant_condition_negative_expression_2.Kconfig
create mode 100644 scripts/kconfig/kconfirm/tests/constant_condition/default_constant_condition_negative_symbol_1.Kconfig
create mode 100644 scripts/kconfig/kconfirm/tests/constant_condition/default_constant_condition_negative_symbol_2.Kconfig
create mode 100644 scripts/kconfig/kconfirm/tests/dead_link.Kconfig
create mode 100644 scripts/kconfig/kconfirm/tests/default_categorization.Kconfig
create mode 100644 scripts/kconfig/kconfirm/tests/pytest.ini
create mode 100644 scripts/kconfig/kconfirm/tests/ranges.Kconfig
create mode 100644 scripts/kconfig/kconfirm/tests/select_imply.Kconfig
create mode 100644 scripts/kconfig/kconfirm/tests/test_kconfirm.py
diff --git a/scripts/kconfig/kconfirm/tests/arch/arm/Kconfig b/scripts/kconfig/kconfirm/tests/arch/arm/Kconfig
new file mode 100644
index 000000000000..5922782a5f4d
--- /dev/null
+++ b/scripts/kconfig/kconfirm/tests/arch/arm/Kconfig
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2026 Julian Braha <julianbraha@gmail.com>
+
+source "architecture_common.Kconfig"
+
+config ARM_ONLY
+ bool
+ depends on ARM_PREREQUISITE
+ depends on ARM_PREREQUISITE
diff --git a/scripts/kconfig/kconfirm/tests/arch/powerpc/Kconfig b/scripts/kconfig/kconfirm/tests/arch/powerpc/Kconfig
new file mode 100644
index 000000000000..45e94dc6cec6
--- /dev/null
+++ b/scripts/kconfig/kconfirm/tests/arch/powerpc/Kconfig
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2026 Julian Braha <julianbraha@gmail.com>
+
+source "architecture_common.Kconfig"
diff --git a/scripts/kconfig/kconfirm/tests/arch/riscv/Kconfig b/scripts/kconfig/kconfirm/tests/arch/riscv/Kconfig
new file mode 100644
index 000000000000..9f760f673064
--- /dev/null
+++ b/scripts/kconfig/kconfirm/tests/arch/riscv/Kconfig
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2026 Julian Braha <julianbraha@gmail.com>
+
+source "architecture_common.Kconfig"
+
+config RISCV_ONLY
+ bool
+ depends on RISCV_PREREQUISITE
+ depends on RISCV_PREREQUISITE
diff --git a/scripts/kconfig/kconfirm/tests/arch/sh/Kconfig b/scripts/kconfig/kconfirm/tests/arch/sh/Kconfig
new file mode 100644
index 000000000000..45e94dc6cec6
--- /dev/null
+++ b/scripts/kconfig/kconfirm/tests/arch/sh/Kconfig
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2026 Julian Braha <julianbraha@gmail.com>
+
+source "architecture_common.Kconfig"
diff --git a/scripts/kconfig/kconfirm/tests/arch/testarch/Kconfig b/scripts/kconfig/kconfirm/tests/arch/testarch/Kconfig
new file mode 100644
index 000000000000..bb5c0e4b3829
--- /dev/null
+++ b/scripts/kconfig/kconfirm/tests/arch/testarch/Kconfig
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2026 Julian Braha <julianbraha@gmail.com>
+
+# Dynamically discovered test architecture.
diff --git a/scripts/kconfig/kconfirm/tests/arch/um/Kconfig b/scripts/kconfig/kconfirm/tests/arch/um/Kconfig
new file mode 100644
index 000000000000..45e94dc6cec6
--- /dev/null
+++ b/scripts/kconfig/kconfirm/tests/arch/um/Kconfig
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2026 Julian Braha <julianbraha@gmail.com>
+
+source "architecture_common.Kconfig"
diff --git a/scripts/kconfig/kconfirm/tests/arch/x86/Kconfig b/scripts/kconfig/kconfirm/tests/arch/x86/Kconfig
new file mode 100644
index 000000000000..45e94dc6cec6
--- /dev/null
+++ b/scripts/kconfig/kconfirm/tests/arch/x86/Kconfig
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2026 Julian Braha <julianbraha@gmail.com>
+
+source "architecture_common.Kconfig"
diff --git a/scripts/kconfig/kconfirm/tests/architecture.Kconfig b/scripts/kconfig/kconfirm/tests/architecture.Kconfig
new file mode 100644
index 000000000000..a4f1c68548b4
--- /dev/null
+++ b/scripts/kconfig/kconfirm/tests/architecture.Kconfig
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2026 Julian Braha <julianbraha@gmail.com>
+
+source "arch/$(SRCARCH)/Kconfig"
diff --git a/scripts/kconfig/kconfirm/tests/architecture_common.Kconfig b/scripts/kconfig/kconfirm/tests/architecture_common.Kconfig
new file mode 100644
index 000000000000..3205d0d59071
--- /dev/null
+++ b/scripts/kconfig/kconfirm/tests/architecture_common.Kconfig
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2026 Julian Braha <julianbraha@gmail.com>
+
+config SHARED_SELECTEE
+ bool "Shared target"
+ help
+ This is a test-only symbol with a visible prompt.
+ Kconfirm uses it as the target of a select statement.
+ The architecture tests verify that selecting this symbol
+ produces the expected select-visible diagnostic.
+
+config SHARED_SELECTOR
+ bool
+ select SHARED_SELECTEE
+
+config SHARED_DEPENDENCY
+ bool
+ depends on SHARED_PREREQUISITE
+ depends on SHARED_PREREQUISITE
diff --git a/scripts/kconfig/kconfirm/tests/conditional_prompt.Kconfig b/scripts/kconfig/kconfirm/tests/conditional_prompt.Kconfig
new file mode 100644
index 000000000000..f2fef6ea874b
--- /dev/null
+++ b/scripts/kconfig/kconfirm/tests/conditional_prompt.Kconfig
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2026 Julian Braha <julianbraha@gmail.com>
+
+config SELECTEE
+ bool "Target" if PROMPT_CONDITION
+ help
+ This is a test-only symbol with a conditional prompt.
+ Kconfirm uses it as the target of a select statement.
+ The test verifies that the prompt condition is included
+ when deciding whether the target is visible.
+
+config SELECTOR
+ bool
+ select SELECTEE
+
+config PROMPT_CONDITION
+ bool
diff --git a/scripts/kconfig/kconfirm/tests/conftest.py b/scripts/kconfig/kconfirm/tests/conftest.py
new file mode 100644
index 000000000000..005681e7e337
--- /dev/null
+++ b/scripts/kconfig/kconfirm/tests/conftest.py
@@ -0,0 +1,93 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2026 Julian Braha <julianbraha@gmail.com>
+
+"""Fixtures for kconfirm regression tests."""
+
+import os
+import subprocess
+from pathlib import Path
+
+import pytest
+
+
+class Kconfirm:
+ """Test kconfirm against Kconfig fixtures."""
+
+ def __init__(self, binary):
+ self._binary = Path(binary).resolve()
+ self._test_dir = Path(__file__).resolve().parent
+
+ def run_cli(self, arguments, *, arch="x86", environment=None,
+ should_succeed=True):
+ """Run kconfirm with an explicit argument list."""
+ command = [str(self._binary), *arguments]
+
+ process_environment = os.environ.copy()
+ process_environment.pop("SRCARCH", None)
+ process_environment.pop("HEADER_ARCH", None)
+ if arch is None:
+ process_environment.pop("ARCH", None)
+ else:
+ process_environment["ARCH"] = arch
+ if environment:
+ process_environment.update(environment)
+
+ process = subprocess.run(
+ command,
+ capture_output=True,
+ cwd=self._test_dir,
+ env=process_environment,
+ check=False,
+ text=True,
+ )
+
+ print("[command]\n{}\n".format(" ".join(command)))
+ print("[retcode]\n{}\n".format(process.returncode))
+ print("[stdout]\n{}".format(process.stdout))
+ print("[stderr]\n{}".format(process.stderr))
+
+ if should_succeed:
+ assert process.returncode == 0
+ else:
+ assert process.returncode != 0
+
+ return process
+
+ def run(self, kconfig, *, arch="x86", enable_check=None,
+ disable_check=None, environment=None, should_succeed=True):
+ """Run kconfirm against one Kconfig fixture."""
+ arguments = [
+ "--linux-path",
+ str(self._test_dir),
+ "--kconfig",
+ kconfig,
+ ]
+
+ if enable_check:
+ arguments.extend(["--enable-check", enable_check])
+ if disable_check:
+ arguments.extend(["--disable-check", disable_check])
+
+ return self.run_cli(
+ arguments,
+ arch=arch,
+ environment=environment,
+ should_succeed=should_succeed,
+ )
+
+
+def pytest_addoption(parser):
+ parser.addoption(
+ "--kconfirm",
+ metavar="PATH",
+ help="path to the kconfirm executable",
+ )
+
+
+@pytest.fixture(scope="session")
+def kconfirm(request):
+ binary = request.config.getoption("--kconfirm")
+ if not binary:
+ raise pytest.UsageError("--kconfirm is required")
+
+ return Kconfirm(binary)
diff --git a/scripts/kconfig/kconfirm/tests/constant_condition/default_constant_condition_negative_expression_1.Kconfig b/scripts/kconfig/kconfirm/tests/constant_condition/default_constant_condition_negative_expression_1.Kconfig
new file mode 100644
index 000000000000..3e3cc1c72ecf
--- /dev/null
+++ b/scripts/kconfig/kconfirm/tests/constant_condition/default_constant_condition_negative_expression_1.Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2026 Julian Braha <julianbraha@gmail.com>
+
+config A
+ tristate
+ depends on !(B || C)
+ default y if B || C
+
+config B
+ bool
+
+config C
+ tristate
diff --git a/scripts/kconfig/kconfirm/tests/constant_condition/default_constant_condition_negative_expression_2.Kconfig b/scripts/kconfig/kconfirm/tests/constant_condition/default_constant_condition_negative_expression_2.Kconfig
new file mode 100644
index 000000000000..64a1778b2981
--- /dev/null
+++ b/scripts/kconfig/kconfirm/tests/constant_condition/default_constant_condition_negative_expression_2.Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2026 Julian Braha <julianbraha@gmail.com>
+
+config A
+ tristate
+ depends on B || C
+ default y if !(B || C)
+
+config B
+ bool
+
+config C
+ tristate
diff --git a/scripts/kconfig/kconfirm/tests/constant_condition/default_constant_condition_negative_symbol_1.Kconfig b/scripts/kconfig/kconfirm/tests/constant_condition/default_constant_condition_negative_symbol_1.Kconfig
new file mode 100644
index 000000000000..34afd2a48396
--- /dev/null
+++ b/scripts/kconfig/kconfirm/tests/constant_condition/default_constant_condition_negative_symbol_1.Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2026 Julian Braha <julianbraha@gmail.com>
+
+config A
+ tristate
+ depends on B
+ default y if !B
+
+config B
+ bool
+
+config C
+ tristate
diff --git a/scripts/kconfig/kconfirm/tests/constant_condition/default_constant_condition_negative_symbol_2.Kconfig b/scripts/kconfig/kconfirm/tests/constant_condition/default_constant_condition_negative_symbol_2.Kconfig
new file mode 100644
index 000000000000..d578b130faab
--- /dev/null
+++ b/scripts/kconfig/kconfirm/tests/constant_condition/default_constant_condition_negative_symbol_2.Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2026 Julian Braha <julianbraha@gmail.com>
+
+config A
+ tristate
+ depends on !B
+ default y if B
+
+config B
+ bool
+
+config C
+ tristate
diff --git a/scripts/kconfig/kconfirm/tests/dead_link.Kconfig b/scripts/kconfig/kconfirm/tests/dead_link.Kconfig
new file mode 100644
index 000000000000..29bce7aa30fc
--- /dev/null
+++ b/scripts/kconfig/kconfirm/tests/dead_link.Kconfig
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2026 Julian Braha <julianbraha@gmail.com>
+
+config HAS_DEAD_LINK
+ bool
+ help
+ The obsolete documentation was at https://example.invalid/obsolete.
+
+config HAS_DUPLICATE_DEAD_LINK
+ bool
+ help
+ The same documentation was at https://example.invalid/obsolete.
diff --git a/scripts/kconfig/kconfirm/tests/default_categorization.Kconfig b/scripts/kconfig/kconfirm/tests/default_categorization.Kconfig
new file mode 100644
index 000000000000..45ff769ad1c8
--- /dev/null
+++ b/scripts/kconfig/kconfirm/tests/default_categorization.Kconfig
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2026 Julian Braha <julianbraha@gmail.com>
+
+config DUPLICATE_UNCONDITIONAL
+ bool
+ default y
+ default y
+
+config DEAD_AFTER_UNCONDITIONAL
+ bool
+ default y
+ default n
+
+config DUPLICATE_CONDITIONAL
+ bool
+ default y if CONDITION
+ default y if CONDITION
+
+config CONDITION
+ bool
diff --git a/scripts/kconfig/kconfirm/tests/pytest.ini b/scripts/kconfig/kconfirm/tests/pytest.ini
new file mode 100644
index 000000000000..2e24f7bc9f2c
--- /dev/null
+++ b/scripts/kconfig/kconfirm/tests/pytest.ini
@@ -0,0 +1,2 @@
+[pytest]
+addopts = --verbose
diff --git a/scripts/kconfig/kconfirm/tests/ranges.Kconfig b/scripts/kconfig/kconfirm/tests/ranges.Kconfig
new file mode 100644
index 000000000000..4ced953247e1
--- /dev/null
+++ b/scripts/kconfig/kconfirm/tests/ranges.Kconfig
@@ -0,0 +1,39 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2026 Julian Braha <julianbraha@gmail.com>
+#
+# Fixture for toggling duplicate_range and dead_range independently of each
+# other, and for categorizing repeated ranges correctly.
+
+config GATE
+ bool
+
+config OTHER_GATE
+ bool
+
+config RANGED_DUP
+ int
+ range 1 5
+ range 1 5
+
+config RANGED_DEAD
+ int
+ range 1 5
+ range 2 6 if GATE
+
+config RANGED_CONDITIONAL_FIRST
+ int
+ range 1 5 if GATE
+ range 2 6
+
+config RANGED_DEAD_UNCONDITIONAL
+ int
+ range 1 5
+ range 2 6
+
+config RANGED_MULTIPLE
+ int
+ range 1 5 if GATE
+ range 2 6 if OTHER_GATE
+ range 3 7
+ range 4 8 if GATE
+ range 5 9
diff --git a/scripts/kconfig/kconfirm/tests/select_imply.Kconfig b/scripts/kconfig/kconfirm/tests/select_imply.Kconfig
new file mode 100644
index 000000000000..ac8f2aa1b66c
--- /dev/null
+++ b/scripts/kconfig/kconfirm/tests/select_imply.Kconfig
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2026 Julian Braha <julianbraha@gmail.com>
+#
+# Fixture for toggling duplicate_select/dead_select and
+# duplicate_imply/dead_imply independently of each other.
+
+config SELECTEE
+ bool
+
+config OTHER_SELECTEE
+ bool
+
+config GATE
+ bool
+
+config SELECTOR
+ bool
+ select SELECTEE
+ select SELECTEE if GATE
+ select OTHER_SELECTEE
+ select OTHER_SELECTEE
+
+config IMPLIER
+ bool
+ imply SELECTEE
+ imply SELECTEE if GATE
+ imply OTHER_SELECTEE
+ imply OTHER_SELECTEE
diff --git a/scripts/kconfig/kconfirm/tests/test_kconfirm.py b/scripts/kconfig/kconfirm/tests/test_kconfirm.py
new file mode 100644
index 000000000000..5e23f7d2b0cb
--- /dev/null
+++ b/scripts/kconfig/kconfirm/tests/test_kconfirm.py
@@ -0,0 +1,358 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2026 Julian Braha <julianbraha@gmail.com>
+
+"""Regression tests for kconfirm."""
+
+import shutil
+from pathlib import Path
+
+import pytest
+
+
+TEST_DIR = Path(__file__).resolve().parent
+
+
+@pytest.mark.parametrize(
+ "fixture",
+ [
+ "default_constant_condition_negative_expression_1.Kconfig",
+ "default_constant_condition_negative_expression_2.Kconfig",
+ "default_constant_condition_negative_symbol_1.Kconfig",
+ "default_constant_condition_negative_symbol_2.Kconfig",
+ ],
+)
+def test_negative_constant_condition(kconfirm, fixture):
+ process = kconfirm.run("constant_condition/{}".format(fixture))
+
+ assert "[constant_condition] [X86] config A:" in process.stdout
+ assert "will always be false" in process.stdout
+
+
+def test_default_categorization(kconfirm):
+ process = kconfirm.run("default_categorization.Kconfig")
+
+ assert (
+ "[duplicate_default] [X86] config DUPLICATE_UNCONDITIONAL: "
+ "duplicate default of y"
+ ) in process.stdout
+ assert (
+ "[dead_default] [X86] config DUPLICATE_UNCONDITIONAL:"
+ ) not in process.stdout
+ assert (
+ "[dead_default] [X86] config DEAD_AFTER_UNCONDITIONAL: "
+ "dead default of n"
+ ) in process.stdout
+ assert (
+ "[duplicate_default] [X86] config DUPLICATE_CONDITIONAL: "
+ "duplicate default of y"
+ ) in process.stdout
+
+
+def test_select_and_imply_checks(kconfirm):
+ process = kconfirm.run("select_imply.Kconfig")
+
+ assert (
+ "[dead_select] [X86] config SELECTOR: dead select of SELECTEE"
+ ) in process.stdout
+ assert (
+ "[dead_imply] [X86] config IMPLIER: dead imply of SELECTEE"
+ ) in process.stdout
+
+
+def test_disable_dead_select_and_imply_checks(kconfirm):
+ process = kconfirm.run(
+ "select_imply.Kconfig",
+ disable_check="dead_select,dead_imply",
+ )
+
+ assert "[dead_select]" not in process.stdout
+ assert "[dead_imply]" not in process.stdout
+ assert (
+ "[duplicate_select] [X86] config SELECTOR: "
+ "duplicate select of OTHER_SELECTEE"
+ ) in process.stdout
+ assert (
+ "[duplicate_imply] [X86] config IMPLIER: "
+ "duplicate imply of OTHER_SELECTEE"
+ ) in process.stdout
+
+
+def test_disable_duplicate_select_and_imply_checks(kconfirm):
+ process = kconfirm.run(
+ "select_imply.Kconfig",
+ disable_check="duplicate_select,duplicate_imply",
+ )
+
+ assert "[duplicate_select]" not in process.stdout
+ assert "[duplicate_imply]" not in process.stdout
+ assert (
+ "[dead_select] [X86] config SELECTOR: dead select of SELECTEE"
+ ) in process.stdout
+ assert (
+ "[dead_imply] [X86] config IMPLIER: dead imply of SELECTEE"
+ ) in process.stdout
+
+
+def test_range_checks(kconfirm):
+ process = kconfirm.run("ranges.Kconfig")
+
+ assert (
+ "[duplicate_range] [X86] config RANGED_DUP: duplicate range 1 5"
+ ) in process.stdout
+ assert "[dead_range] [X86] config RANGED_DUP:" not in process.stdout
+ assert (
+ "[dead_range] [X86] config RANGED_DEAD: dead range of 2 6"
+ ) in process.stdout
+ assert (
+ "[dead_range] [X86] config RANGED_DEAD_UNCONDITIONAL: "
+ "dead range of 2 6"
+ ) in process.stdout
+ assert (
+ "[dead_range] [X86] config RANGED_CONDITIONAL_FIRST:"
+ ) not in process.stdout
+ assert process.stdout.count(
+ "[dead_range] [X86] config RANGED_MULTIPLE:"
+ ) == 2
+
+
+def test_disable_dead_range_check(kconfirm):
+ process = kconfirm.run(
+ "ranges.Kconfig",
+ disable_check="dead_range",
+ )
+
+ assert "[dead_range]" not in process.stdout
+ assert (
+ "[duplicate_range] [X86] config RANGED_DUP: duplicate range 1 5"
+ ) in process.stdout
+
+
+def test_disable_duplicate_range_check(kconfirm):
+ process = kconfirm.run(
+ "ranges.Kconfig",
+ disable_check="duplicate_range",
+ )
+
+ assert "[duplicate_range]" not in process.stdout
+ assert (
+ "[dead_range] [X86] config RANGED_DEAD: dead range of 2 6"
+ ) in process.stdout
+
+
+def test_architecture_directory_is_discovered(kconfirm):
+ process = kconfirm.run(
+ "default_categorization.Kconfig",
+ arch="testarch",
+ )
+
+ assert (
+ "[duplicate_default] [TESTARCH] config DUPLICATE_UNCONDITIONAL:"
+ ) in process.stdout
+
+
+def test_unknown_architecture_is_rejected(kconfirm):
+ process = kconfirm.run(
+ "conditional_prompt.Kconfig",
+ arch="missing",
+ should_succeed=False,
+ )
+ output = process.stdout + process.stderr
+
+ assert "unexpected architecture from ARCH" in output
+ for architecture in ["arm", "powerpc", "riscv", "sh", "testarch", "um", "x86"]:
+ assert architecture in output
+
+
+def test_missing_architecture_is_rejected(kconfirm):
+ process = kconfirm.run(
+ "conditional_prompt.Kconfig",
+ arch=None,
+ should_succeed=False,
+ )
+
+ assert "ARCH environment variable is required" in process.stderr
+
+
+def test_conditional_prompt_is_not_select_visible(kconfirm):
+ process = kconfirm.run(
+ "conditional_prompt.Kconfig",
+ enable_check="select_visible",
+ )
+
+ assert "[select_visible]" not in process.stdout
+
+
+@pytest.mark.parametrize(
+ ("arch", "arch_config", "specific_symbol", "specific_dependency"),
+ [
+ ("arm", "ARM", "ARM_ONLY", "ARM_PREREQUISITE"),
+ ("riscv", "RISCV", "RISCV_ONLY", "RISCV_PREREQUISITE"),
+ ],
+)
+def test_architecture_findings(
+ kconfirm,
+ arch,
+ arch_config,
+ specific_symbol,
+ specific_dependency,
+):
+ process = kconfirm.run(
+ "architecture.Kconfig",
+ arch=arch,
+ enable_check="select_visible",
+ )
+
+ assert (
+ f"[duplicate_dependency] [{arch_config}] config SHARED_DEPENDENCY: "
+ "duplicate dependency on SHARED_PREREQUISITE"
+ ) in process.stdout
+ assert (
+ f"[select_visible] [{arch_config}] config SHARED_SELECTOR: "
+ "selects the visible SHARED_SELECTEE"
+ ) in process.stdout
+ assert (
+ f"[duplicate_dependency] [{arch_config}] config {specific_symbol}: "
+ f"duplicate dependency on {specific_dependency}"
+ ) in process.stdout
+
+
+@pytest.mark.parametrize(
+ ("arch", "arch_config"),
+ [
+ ("x86_64", "X86"),
+ ("powerpc", "PPC"),
+ ("sh", "SUPERH"),
+ ("um", "UML"),
+ ],
+)
+def test_architecture_alias_selects_source_directory(kconfirm, arch, arch_config):
+ process = kconfirm.run(
+ "architecture.Kconfig",
+ arch=arch,
+ enable_check="select_visible",
+ )
+
+ assert (
+ f"[duplicate_dependency] [{arch_config}] config SHARED_DEPENDENCY: "
+ "duplicate dependency on SHARED_PREREQUISITE"
+ ) in process.stdout
+
+
+@pytest.mark.skipif(shutil.which("curl") is None, reason="requires curl")
+def test_dead_links_are_deduplicated(kconfirm):
+ # Both fixture config options point at the same example.invalid URL. That
+ # TLD is reserved and never resolves (RFC 6761), so curl should fail
+ # deterministically, and the link reported once. The second config option
+ # referencing it should be deduplicated.
+ process = kconfirm.run(
+ "dead_link.Kconfig",
+ enable_check="dead_link",
+ )
+
+ assert (
+ "[dead_link] [X86] config HAS_DEAD_LINK:"
+ ) in process.stdout
+ assert (
+ "[dead_link] [X86] config HAS_DUPLICATE_DEAD_LINK:"
+ ) not in process.stdout
+
+
+def test_dead_link_requires_curl(kconfirm):
+ process = kconfirm.run(
+ "dead_link.Kconfig",
+ enable_check="dead_link",
+ environment={"PATH": ""},
+ should_succeed=False,
+ )
+
+ assert "dead_link requires the `curl` command" in process.stderr
+
+
+@pytest.mark.parametrize(
+ "arguments",
+ [
+ [
+ f"--linux-path={TEST_DIR}",
+ "--kconfig=conditional_prompt.Kconfig",
+ "--enable-check=select_visible",
+ "--disable-check=dead_range",
+ ],
+ [
+ f"-l{TEST_DIR}",
+ "-kconditional_prompt.Kconfig",
+ "-eselect_visible",
+ "-ddead_range",
+ ],
+ ],
+)
+def test_attached_option_values(kconfirm, arguments):
+ process = kconfirm.run_cli(arguments)
+
+ assert "[select_visible]" not in process.stdout
+
+
+def test_repeated_check_options(kconfirm):
+ process = kconfirm.run_cli(
+ [
+ "--linux-path",
+ str(TEST_DIR),
+ "--kconfig",
+ "conditional_prompt.Kconfig",
+ "--enable-check",
+ "select_visible",
+ "--enable-check",
+ "duplicate_default_value",
+ "--disable-check",
+ "dead_range",
+ "--disable-check",
+ "reverse_range",
+ ],
+ )
+
+ assert process.stderr == ""
+
+
+def test_help(kconfirm):
+ process = kconfirm.run_cli(["--help"])
+
+ assert "Usage: kconfirm --linux-path PATH" in process.stdout
+
+
+@pytest.mark.parametrize(
+ ("arguments", "message"),
+ [
+ ([], "--linux-path is required"),
+ (["--unknown"], "unrecognized option '--unknown'"),
+ (
+ [
+ "--linux-path",
+ str(TEST_DIR),
+ "--enable-check",
+ "not_a_check",
+ ],
+ "check not_a_check does not exist",
+ ),
+ (
+ [
+ "--linux-path",
+ str(TEST_DIR),
+ "--enable-check",
+ "ungrouped_attribute",
+ ],
+ "check ungrouped_attribute does not exist",
+ ),
+ ],
+)
+def test_cli_errors(kconfirm, arguments, message):
+ process = kconfirm.run_cli(arguments, should_succeed=False)
+
+ assert message in process.stdout + process.stderr
+
+
+def test_invalid_linux_path(kconfirm):
+ process = kconfirm.run_cli(
+ ["--linux-path", str(TEST_DIR / "does-not-exist")],
+ should_succeed=False,
+ )
+
+ assert "No such file or directory" in process.stderr
--
2.54.0
next prev parent reply other threads:[~2026-07-27 0:16 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-27 0:16 [PATCH v4 0/5] add kconfirm Julian Braha
2026-07-27 0:16 ` [PATCH v4 1/5] kconfig: add add another callback to the parser to view raw parse tree Julian Braha
2026-07-27 0:16 ` [PATCH 2/5] kconfig: add kconfirm Julian Braha
2026-07-27 0:16 ` Julian Braha [this message]
2026-07-27 0:16 ` [PATCH v4 4/5] Documentation: " Julian Braha
2026-07-27 0:16 ` [PATCH v4 5/5] MAINTAINERS: add entry for kconfirm Julian Braha
2026-09-04 12:29 ` [PATCH v4 0/5] add kconfirm Julian Braha
2026-09-04 18:37 ` Nicolas Schier
2026-09-04 22:05 ` Nathan Chancellor
2026-09-06 15:22 ` Julian Braha
2026-09-07 8:34 ` Nicolas Schier
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260727001623.2794156-4-julianbraha@gmail.com \
--to=julianbraha@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=andrew.jones@linux.dev \
--cc=arnd@arndb.de \
--cc=corbet@lwn.net \
--cc=demiobenour@gmail.com \
--cc=ej@inai.de \
--cc=gary@garyguo.net \
--cc=gregkh@linuxfoundation.org \
--cc=jani.nikula@linux.intel.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kbuild@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=ljs@kernel.org \
--cc=masahiroy@kernel.org \
--cc=nathan@kernel.org \
--cc=nsc@kernel.org \
--cc=ojeda@kernel.org \
--cc=qingfang.deng@linux.dev \
--cc=rust-for-linux@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.