Repository: bitcoin/bitcoin
File: test/functional/test_runner.py (Python)

Code before:
        #   `test/functional/test_runner.py ./test/functional/wallet*`
        #   `test_runner.py wallet*`
        #   but not:
        #   `test/functional/test_runner.py wallet*`
        # Multiple wildcards can be passed:
        #   `test_runner.py tool* mempool*`
        for test in tests:
            script = test.split("/")[-1]
            script = script + ".py" if ".py" not in script else script
            matching_scripts = [s for s in ALL_SCRIPTS if s.startswith(script)]
            if matching_scripts:
                test_list.extend(matching_scripts)
            else:
                print("{}WARNING!{} Test '{}' not found in full test list.".format(BOLD[1], BOLD[0], test))
    elif args.extended:
        # Include extended tests
        test_list += ALL_SCRIPTS
    else:
        # Run base tests only
        test_list += BASE_SCRIPTS

    # Remove the test cases that the user has explicitly asked to exclude.
    if args.exclude:
        def print_warning_missing_test(test_name):
            print("{}WARNING!{} Test '{}' not found in current test list.".format(BOLD[1], BOLD[0], test_name))
        exclude_tests = [test.strip() for test in args.exclude.split(",")]
        for exclude_test in exclude_tests:
            if exclude_test.endswith('.py'):
                # Remove <test_name>.py and <test_name>.py --arg from the test list
                exclude_list = [test for test in test_list if test.split('.py')[0] == exclude_test.split('.py')[0]]
                if not exclude_list:
                    print_warning_missing_test(exclude_test)
                for exclude_item in exclude_list:
                    test_list.remove(exclude_item)
            else:
                try:
                    test_list.remove(exclude_test)
                except ValueError:
                    print_warning_missing_test(exclude_test)

    if args.filter:
        test_list = list(filter(re.compile(args.filter).search, test_list))

    if not test_list:
        print("No valid test scripts specified. Check that your test is in one "
              "of the test lists in test_runner.py, or run test_runner.py with no arguments to run all tests")
        sys.exit(1)

    if args.help:
        # Print help for test_runner.py, then print help of the first script (with args removed) and exit.
        parser.print_help()

Review comment (bug):
Another way this would have been caught is by making warnings in the CI fatal. There is `fail_on_warn=args.ci` which can be used.

Code after:
        #   `test/functional/test_runner.py ./test/functional/wallet*`
        #   `test_runner.py wallet*`
        #   but not:
        #   `test/functional/test_runner.py wallet*`
        # Multiple wildcards can be passed:
        #   `test_runner.py tool* mempool*`
        for test in tests:
            script = test.split("/")[-1]
            script = script + ".py" if ".py" not in script else script
            matching_scripts = [s for s in ALL_SCRIPTS if s.startswith(script)]
            if matching_scripts:
                test_list.extend(matching_scripts)
            else:
                print("{}WARNING!{} Test '{}' not found in full test list.".format(BOLD[1], BOLD[0], test))
    elif args.extended:
        # Include extended tests
        test_list += ALL_SCRIPTS
    else:
        # Run base tests only
        test_list += BASE_SCRIPTS

    # Remove the test cases that the user has explicitly asked to exclude.
    # The user can specify a test case with or without the .py extension.
    if args.exclude:
        def print_warning_missing_test(test_name):
            print("{}WARNING!{} Test '{}' not found in current test list.".format(BOLD[1], BOLD[0], test_name))
        def remove_tests(exclude_list):
            if not exclude_list:
                print_warning_missing_test(exclude_test)
            for exclude_item in exclude_list:
                test_list.remove(exclude_item)

        exclude_tests = [test.strip() for test in args.exclude.split(",")]
        for exclude_test in exclude_tests:
            # A space in the name indicates it has arguments such as "wallet_basic.py --descriptors"
            if ' ' in exclude_test:
                remove_tests([test for test in test_list if test.replace('.py', '') == exclude_test.replace('.py', '')])
            else:
                # Exclude all variants of a test
                remove_tests([test for test in test_list if test.split('.py')[0] == exclude_test.split('.py')[0]])

    if args.filter:
        test_list = list(filter(re.compile(args.filter).search, test_list))

    if not test_list:
        print("No valid test scripts specified. Check that your test is in one "
              "of the test lists in test_runner.py, or run test_runner.py with no arguments to run all tests")
        sys.exit(1)

    if args.help:
        # Print help for test_runner.py, then print help of the first script (with args removed) and exit.