[PATCH v4 3/5] kconfirm: add tests
From: Julian Braha
Date: Sun Jul 26 2026 - 20:17:42 EST
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@xxxxxxxxx>
---
.../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@xxxxxxxxx>
+
+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@xxxxxxxxx>
+
+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@xxxxxxxxx>
+
+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@xxxxxxxxx>
+
+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@xxxxxxxxx>
+
+# 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@xxxxxxxxx>
+
+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@xxxxxxxxx>
+
+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@xxxxxxxxx>
+
+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@xxxxxxxxx>
+
+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@xxxxxxxxx>
+
+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@xxxxxxxxx>
+
+"""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@xxxxxxxxx>
+
+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@xxxxxxxxx>
+
+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@xxxxxxxxx>
+
+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@xxxxxxxxx>
+
+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@xxxxxxxxx>
+
+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@xxxxxxxxx>
+
+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@xxxxxxxxx>
+#
+# 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@xxxxxxxxx>
+#
+# 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@xxxxxxxxx>
+
+"""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