From patchwork Tue Sep 9 15:18:15 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 278 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1757431186; bh=VbKqRp5SIkEU4GX+sEyNEe258SBmqN1hYpuFaNuOHJc=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=TDwaNy0IF2nISqrGRSacOQKzE67MXUmp4MAx8udz2BMoVhQdd/HgpTA0mJ2Z8SAts Zh4IiUzs+XyadZuunAhsu0xWlT2WlLjX3I0oPRjyLitmm4Dw0XLYQ+wlAICr2oGdn4 zV3awn7n4Ih14vwLGQgYCzjrFdVP3X/AJGewRc3+LmGl6lTDEoqx/LnVgglMhRZjBF zF70HbAHB/h0rioZJx9a5UISkQk6FLVPNp9WA68yWyxjUqTjc5jKw4XYiv8YyhQmfc Do7DAGoDcUvA997m2NzjSdlcG2/tSNksNGZF9sXyjNTd8g80kk2IgafShTRHLAhNa4 s/+Ac9JpL1f4A== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 742E1679F7 for ; Tue, 9 Sep 2025 09:19:46 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id DLynk9d8oUmo for ; Tue, 9 Sep 2025 09:19:46 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1757431186; bh=VbKqRp5SIkEU4GX+sEyNEe258SBmqN1hYpuFaNuOHJc=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=TDwaNy0IF2nISqrGRSacOQKzE67MXUmp4MAx8udz2BMoVhQdd/HgpTA0mJ2Z8SAts Zh4IiUzs+XyadZuunAhsu0xWlT2WlLjX3I0oPRjyLitmm4Dw0XLYQ+wlAICr2oGdn4 zV3awn7n4Ih14vwLGQgYCzjrFdVP3X/AJGewRc3+LmGl6lTDEoqx/LnVgglMhRZjBF zF70HbAHB/h0rioZJx9a5UISkQk6FLVPNp9WA68yWyxjUqTjc5jKw4XYiv8YyhQmfc Do7DAGoDcUvA997m2NzjSdlcG2/tSNksNGZF9sXyjNTd8g80kk2IgafShTRHLAhNa4 s/+Ac9JpL1f4A== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 63A4E679D6 for ; Tue, 9 Sep 2025 09:19:46 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1757431184; bh=aq3+Iq5usYVa8X5Dc3r6MUHFlJVO5UMrUZwZVnM6/Xg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bN6O5Ia+spxhvfF33DNO3HjMBBYOaXSoOir936WU5EqnpCgw7com0nhApc8uLCcwO AHsHuwdmcEk5nBOrzAUnXDu0jbj+mEpfDZP3U+8J9EKtvNk+Sp+ByZEQavvYX4znf8 GfVQ2nQ+Fo4GAisw0Mh46mDzDJvCEUB4ByKkAXzXCPnRQhmw+E/yrQFiBPYTyLvNHO dhJGSmgpBda1wZKsyNKs0J4rlPrYcGaPYpDFFpO5WXCfDPh8AJudsRl5YulJrUSegI 8gpX9IqOQIJ8Tlre4Cqf8XOpiwyVFrAM2DQOSaBL3tybqywWiBRx4xzFHsQbW5cHXw oVVgQEi4oqKAA== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 54EF5679E6; Tue, 9 Sep 2025 09:19:44 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id IH_mXen_UuTK; Tue, 9 Sep 2025 09:19:44 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1757431179; bh=9dAFWrs1Q98yDWhAGl4iLGTCsYNleskvhKw5T9RyBe0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bQv+l01sOp5YjroLXFJjcvE0HM9FzHfKL2Yf6UhyKCRKMFzNktibyDxcW3CbHPK7/ JZu8lfSflMFSbNm81IWTqnkwxr+DWFxQMYnFLWXRjd4//NplPli+e6Q6SdkXm1+JyP ElG6/JYhWCLYfY9kx2cm5lmoC5/ZydBTfFP7pHf4qGh+AJ27qaq+LZ8kwP4K7JQDDS YQWIspmU+PeSnz3N9aCbOI8k4blkMrirchg3WHZJmlOO20OhQ1zKeamyc0nqWeIpA2 ATtOG0zp5o87SyX5EmYSp3yU0JbGwEBEFPcwMH3d9swVKihtakFhu/lFCFP1S2/dO5 vRhpXlwsifnWA== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id C1E4A60026; Tue, 9 Sep 2025 09:19:38 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Tue, 9 Sep 2025 09:18:15 -0600 Message-ID: <20250909151824.2327219-19-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250909151824.2327219-1-sjg@u-boot.org> References: <20250909151824.2327219-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: 2Q2LGKBIE2W55DPK7BYXIPEFEKYR55QT X-Message-ID-Hash: 2Q2LGKBIE2W55DPK7BYXIPEFEKYR55QT X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Heinrich Schuchardt , Simon Glass , Claude X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 18/18] test/py: Add a test for ulib functionality List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass Provide a test that checks that ulib operates as expected. Add a .gitignore file for the executables thus created There is a strange interaction with PLATFORM_LIBS which can cause the examples to fail to build via 'make qcheck': - CI runs 'make qcheck' - the main Makefile sets PLATFORM_LIBS - test/run calls test.py - at some point test_ulib_demos() starts, with PLATFORM_LIBS set - the test calls 'make' on examples/ulib/Makefile - PLATFORM_LIBS is left alone, since it already has a value - lSDL ends up not being in the link line Thank you to Claude for helping to debug this and figure out the PLATFORM_LIBS interaction. Co-developed-by: Claude Signed-off-by: Simon Glass --- examples/ulib/.gitignore | 2 + examples/ulib/demo_helper.c | 10 +-- test/py/tests/test_ulib.py | 141 ++++++++++++++++++++++++++++++++++++ test/run | 8 ++ 4 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 examples/ulib/.gitignore create mode 100644 test/py/tests/test_ulib.py diff --git a/examples/ulib/.gitignore b/examples/ulib/.gitignore new file mode 100644 index 00000000000..d2f0dfa7a93 --- /dev/null +++ b/examples/ulib/.gitignore @@ -0,0 +1,2 @@ +/demo +/demo_static diff --git a/examples/ulib/demo_helper.c b/examples/ulib/demo_helper.c index 935443657bd..e3a2c6bdcfb 100644 --- a/examples/ulib/demo_helper.c +++ b/examples/ulib/demo_helper.c @@ -10,21 +10,19 @@ void demo_show_banner(void) { - ub_printf("=================================\n"); - ub_printf(" U-Boot Library Demo Helper\n"); - ub_printf("=================================\n"); + ub_printf("U-Boot Library Demo Helper\n"); + ub_printf("==========================\n"); } void demo_show_footer(void) { ub_printf("=================================\n"); - ub_printf(" Demo Complete!\n"); - ub_printf("=================================\n"); + ub_printf("Demo complete\n"); } int demo_add_numbers(int a, int b) { - ub_printf("Helper: Adding %d + %d = %d\n", a, b, a + b); + ub_printf("helper: Adding %d + %d = %d\n", a, b, a + b); return a + b; } diff --git a/test/py/tests/test_ulib.py b/test/py/tests/test_ulib.py new file mode 100644 index 00000000000..76d40e1385c --- /dev/null +++ b/test/py/tests/test_ulib.py @@ -0,0 +1,141 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2025, Canonical Ltd. + +import os +import subprocess +import pytest +import utils + +def check_output(out): + """Check output from the ulib test""" + assert 'Hello, world from ub_printf' in out + assert '- U-Boot' in out + assert 'Uses libc printf before ulib_init' in out + assert 'another printf()' in out + +@pytest.mark.buildconfigspec("ulib") +def test_ulib_shared(ubman): + """Test the ulib shared library test program""" + + build = ubman.config.build_dir + prog = os.path.join(build, 'test', 'ulib', 'ulib_test') + + # Skip test if ulib_test doesn't exist (clang) + if not os.path.exists(prog): + pytest.skip('ulib_test not found - library build may be disabled') + + out = utils.run_and_log(ubman, [prog], cwd=build) + check_output(out) + assert 'dynamically linked' in out + +@pytest.mark.boardspec('sandbox') +def test_ulib_static(ubman): + """Test the ulib static library test program""" + + build = ubman.config.build_dir + prog = os.path.join(build, 'test', 'ulib', 'ulib_test_static') + + # Skip test if ulib_test_static doesn't exist (clang) + if not os.path.exists(prog): + pytest.skip('ulib_test_static not found - library build may be disabled') + + out = utils.run_and_log(ubman, [prog]) + check_output(out) + assert 'statically linked' in out + +def check_demo_output(ubman, out): + """Check output from the ulib demo programs exactly line by line""" + lines = out.split('\n') + + # Read the actual system version from /proc/version + with open('/proc/version', 'r', encoding='utf-8') as f: + proc_version = f.read().strip() + + expected = [ + 'U-Boot Library Demo Helper\r', + '==========================\r', + 'System version:helper: Adding 42 + 13 = 55\r', + '=================================\r', + 'Demo complete\r', + f'U-Boot version: {ubman.u_boot_version_string}', + '', + f' {proc_version}', + '', + 'Read 1 line(s) using U-Boot library functions.', + 'Helper function result: 55', + '' + ] + + assert len(lines) == len(expected), \ + f"Expected {len(expected)} lines, got {len(lines)}" + + for i, expected in enumerate(expected): + # Exact match for all other lines + assert lines[i] == expected, \ + f"Line {i}: expected '{expected}', got '{lines[i]}'" + +@pytest.mark.boardspec('sandbox') +def test_ulib_demos(ubman): + """Test both ulib demo programs (dynamic and static).""" + + build = ubman.config.build_dir + src = ubman.config.source_dir + examples = os.path.join(src, 'examples', 'ulib') + test_program = os.path.join(build, 'test', 'ulib', 'ulib_test') + + # Skip test if ulib_test doesn't exist (clang) + if not os.path.exists(test_program): + pytest.skip('ulib_test not found - library build may be disabled') + + # Build the demo programs - clean first to ensure fresh build, since this + # test is run in the source directory + cmd = ['make', 'clean'] + utils.run_and_log(ubman, cmd, cwd=examples) + + cmd = ['make', f'UBOOT_BUILD={os.path.abspath(build)}', f'srctree={src}'] + utils.run_and_log(ubman, cmd, cwd=examples) + + # Test static demo program + demo_static = os.path.join(examples, 'demo_static') + out_static = utils.run_and_log(ubman, [demo_static]) + check_demo_output(ubman, out_static) + + # Test dynamic demo program (with proper LD_LIBRARY_PATH) + demo = os.path.join(examples, 'demo') + env = os.environ.copy() + env['LD_LIBRARY_PATH'] = os.path.abspath(build) + out_dynamic = utils.run_and_log(ubman, [demo], env=env) + check_demo_output(ubman, out_dynamic) + +@pytest.mark.boardspec('sandbox') +def test_ulib_api_header(ubman): + """Test that the u-boot-api.h header is generated correctly.""" + + hdr = os.path.join(ubman.config.build_dir, 'include', 'u-boot-api.h') + + # Skip if header doesn't exist (clang) + if not os.path.exists(hdr): + pytest.skip('u-boot-api.h not found - library build may be disabled') + + # Read and verify header content + with open(hdr, 'r', encoding='utf-8') as inf: + out = inf.read() + + # Check header guard + assert '#ifndef __ULIB_API_H' in out + assert '#define __ULIB_API_H' in out + assert '#endif /* __ULIB_API_H */' in out + + # Check required includes + assert '#include ' in out + assert '#include ' in out + + # Check for renamed function declarations + assert 'ub_printf' in out + assert 'ub_snprintf' in out + assert 'ub_vprintf' in out + + # Check that functions have proper signatures + assert 'ub_printf(const char *fmt, ...)' in out + assert 'ub_snprintf(char *buf, size_t size, const char *fmt, ...)' in out + assert 'ub_vprintf(const char *fmt, va_list args)' in out diff --git a/test/run b/test/run index 2ba8324a0c4..80f79317aed 100755 --- a/test/run +++ b/test/run @@ -18,6 +18,14 @@ quiet=-q # Clean up things the Makefile created unset MAKE MAKEFLAGS MAKELEVEL MAKEOVERRIDES MAKE_TERMERR MAKE_TERMOUT +# Unset this since this script is generally run from 'make qcheck' et al, which +# targets are in no-dot-config-targets and thus dot-config is 0 and thus +# config.mk was not included in the main Makefile, thus PLATFORM_LIBS does not +# have the arch-specific settings (e.g. SDL libraries on sandbox). Better to +# leave it empty than have it be wrong. This particularly affects +# example/ulib/Makefile when called from 'make qcheck' +unset PLATFORM_LIBS + # Select test attributes ut_mark_expr=test_ut if [ "$1" = "quick" ]; then