1#!/usr/bin/env python3
2# Copyright (c) 2024 Intel Corporation
3#
4# SPDX-License-Identifier: Apache-2.0
5"""
6Blackbox tests for twister's command line functions related to Twister's tooling.
7"""
8# pylint: disable=duplicate-code
9
10from unittest import mock
11import os
12import pytest
13import sys
14import json
15
16# pylint: disable=no-name-in-module
17from conftest import TEST_DATA, sample_filename_mock, suite_filename_mock
18from twisterlib.statuses import TwisterStatus
19from twisterlib.testplan import TestPlan
20from twisterlib.twister_main import main as twister_main
21
22
23class TestTooling:
24
25    @pytest.mark.parametrize(
26        'jobs',
27        ['1', '2'],
28        ids=['single job', 'two jobs']
29    )
30    @mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', suite_filename_mock)
31    def test_jobs(self, out_path, jobs):
32        test_platforms = ['qemu_x86', 'intel_adl_crb']
33        path = os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic', 'group2')
34        args = ['-i', '--outdir', out_path, '-T', path] + \
35               ['--jobs', jobs] + \
36               [val for pair in zip(
37                   ['-p'] * len(test_platforms), test_platforms
38               ) for val in pair]
39
40
41        return_value = twister_main(args)
42
43        with open(os.path.join(out_path, 'twister.log')) as f:
44            log = f.read()
45            assert f'JOBS: {jobs}' in log
46
47        assert return_value == 0
48
49    @mock.patch.object(TestPlan, 'SAMPLE_FILENAME', sample_filename_mock)
50    def test_force_toolchain(self, out_path):
51        # nsim_vpx5 is one of the rare platforms that do not support the zephyr toolchain
52        test_platforms = ['nsim/nsim_vpx5']
53        path = os.path.join(TEST_DATA, 'samples', 'hello_world')
54        args = ['-i', '--outdir', out_path, '-T', path, '-y'] + \
55               ['--force-toolchain'] + \
56               [] + \
57               [val for pair in zip(
58                   ['-p'] * len(test_platforms), test_platforms
59               ) for val in pair]
60
61        return_value = twister_main(args)
62
63        with open(os.path.join(out_path, 'testplan.json')) as f:
64            j = json.load(f)
65        filtered_j = [
66            (ts['platform'], ts['name'], tc['identifier'], tc['status']) \
67                for ts in j['testsuites'] \
68                for tc in ts['testcases']
69        ]
70
71        # Normally, board not supporting our toolchain would be filtered, so we check against that
72        assert len(filtered_j) == 1
73        assert filtered_j[0][3] != TwisterStatus.FILTER
74
75        assert return_value == 0
76
77    @pytest.mark.parametrize(
78        'test_path, test_platforms',
79        [
80            (
81                os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'),
82                ['qemu_x86'],
83            )
84        ],
85        ids=[
86            'ninja',
87        ]
88    )
89    @pytest.mark.parametrize(
90        'flag',
91        ['--ninja', '-N']
92    )
93    @mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', suite_filename_mock)
94    def test_ninja(self, capfd, out_path, test_path, test_platforms, flag):
95        args = ['--outdir', out_path, '-T', test_path, flag] + \
96               [val for pair in zip(
97                   ['-p'] * len(test_platforms), test_platforms
98               ) for val in pair]
99
100        return_value = twister_main(args)
101
102        out, err = capfd.readouterr()
103        sys.stdout.write(out)
104        sys.stderr.write(err)
105
106        assert return_value == 0
107