#!/usr/bin/env python3 # Copyright (c) 2023 Intel Corporation # # SPDX-License-Identifier: Apache-2.0 """ Tests for cmakecache.py classes' methods """ import mock import pytest from contextlib import nullcontext from twisterlib.cmakecache import CMakeCacheEntry, CMakeCache TESTDATA_1 = [ ('ON', True), ('YES', True), ('TRUE', True), ('Y', True), ('OFF', False), ('NO', False), ('FALSE', False), ('N', False), ('IGNORE', False), ('NOTFOUND', False), ('', False), ('DUMMY-NOTFOUND', False), ('1', True), ('0', False), ('I AM NOT A PROPER VALUE', ValueError), ] @pytest.mark.parametrize( 'cmake_bool, expected_bool', TESTDATA_1, ids=[t[0] for t in TESTDATA_1] ) def test_cmakecacheentry_to_bool(cmake_bool, expected_bool): with pytest.raises(expected_bool) if \ not isinstance(expected_bool, bool) else nullcontext() as exception: b = CMakeCacheEntry._to_bool(cmake_bool) if exception is None: assert b == expected_bool else: assert str(exception.value) == f'invalid bool {cmake_bool}' TESTDATA_2 = [ ( '// I am a comment', None ), ( '# I am a comment too', None ), ( ' \r\n ', None ), ( 'DUMMY:WRONG_TYPE=???', None ), ( 'DUMMY_VALUE_NAME1:STRING=I am a dummy string', CMakeCacheEntry('DUMMY_VALUE_NAME1', 'I am a dummy string') ), ( 'DUMMY_VALUE_NAME2:STRING=list_el1;list_el2;list_el3', CMakeCacheEntry( 'DUMMY_VALUE_NAME2', ['list_el1', 'list_el2', 'list_el3'] ) ), ( 'DUMMY_VALUE_NAME3:INTERNAL=I am a dummy internal string', CMakeCacheEntry('DUMMY_VALUE_NAME3', 'I am a dummy internal string')), ( 'DUMMY_VALUE_NAME4:INTERNAL=list_el1;list_el2', CMakeCacheEntry('DUMMY_VALUE_NAME4', ['list_el1', 'list_el2']) ), ( 'DUMMY_VALUE_NAME5:FILEPATH=/path/to/dir', CMakeCacheEntry('DUMMY_VALUE_NAME5', '/path/to/dir') ), ( 'DUMMY_VALUE_NAME6:PATH=/path/to/dir/file.txt', CMakeCacheEntry('DUMMY_VALUE_NAME6', '/path/to/dir/file.txt')), ( 'DUMMY_VALUE_NAME7:BOOL=Y', CMakeCacheEntry('DUMMY_VALUE_NAME7', True) ), ( 'DUMMY_VALUE_NAME8:BOOL=FALSE', CMakeCacheEntry('DUMMY_VALUE_NAME8', False) ), ( 'DUMMY_VALUE_NAME9:BOOL=NOT_A_BOOL', ValueError( ( 'invalid bool NOT_A_BOOL', 'on line 7: DUMMY_VALUE_NAME9:BOOL=NOT_A_BOOL' ) ) ), ] @pytest.mark.parametrize( 'cmake_line, expected', TESTDATA_2, ids=[ '// comment', '# comment', 'whitespace', 'unrecognised type', 'string', 'string list', 'internal string', 'internal list', 'filepath', 'path', 'true bool', 'false bool', 'not a bool' ] ) def test_cmakecacheentry_from_line(cmake_line, expected): cmake_line_number = 7 with pytest.raises(type(expected)) if \ isinstance(expected, Exception) else nullcontext() as exception: entry = CMakeCacheEntry.from_line(cmake_line, cmake_line_number) if exception is not None: assert repr(exception.value) == repr(expected) return if expected is None: assert entry is None return assert entry.name == expected.name assert entry.value == expected.value TESTDATA_3 = [ ( CMakeCacheEntry('DUMMY_NAME1', 'dummy value'), 'CMakeCacheEntry(name=DUMMY_NAME1, value=dummy value)' ), ( CMakeCacheEntry('DUMMY_NAME2', False), 'CMakeCacheEntry(name=DUMMY_NAME2, value=False)' ) ] @pytest.mark.parametrize( 'cmake_cache_entry, expected', TESTDATA_3, ids=['string value', 'bool value'] ) def test_cmakecacheentry_str(cmake_cache_entry, expected): assert str(cmake_cache_entry) == expected def test_cmakecache_load(): file_data = ( 'DUMMY_NAME1:STRING=First line\n' '//Comment on the second line\n' 'DUMMY_NAME2:STRING=Third line\n' 'DUMMY_NAME3:STRING=Fourth line\n' ) with mock.patch('builtins.open', mock.mock_open(read_data=file_data)): cache = CMakeCache.from_file('dummy/path/CMakeCache.txt') assert cache.cache_file == 'dummy/path/CMakeCache.txt' expected = [ ('DUMMY_NAME1', 'First line'), ('DUMMY_NAME2', 'Third line'), ('DUMMY_NAME3', 'Fourth line') ] for expect in reversed(expected): item = cache._entries.popitem() assert item[0] == expect[0] assert item[1].name == expect[0] assert item[1].value == expect[1] def test_cmakecache_get(): file_data = 'DUMMY_NAME:STRING=Dummy value' with mock.patch('builtins.open', mock.mock_open(read_data=file_data)): cache = CMakeCache.from_file('dummy/path/CMakeCache.txt') good_val = cache.get('DUMMY_NAME') assert good_val == 'Dummy value' bad_val = cache.get('ANOTHER_NAME') assert bad_val is None bad_val = cache.get('ANOTHER_NAME', default='No such value') assert bad_val == 'No such value' TESTDATA_4 = [ ('STRING=el1;el2;el3;el4', True, ['el1', 'el2', 'el3', 'el4']), ('STRING=dummy value', True, ['dummy value']), ('STRING=', True, []), ('BOOL=True', True, RuntimeError), ('STRING=dummy value', False, []), ] @pytest.mark.parametrize( 'value, correct_get, expected', TESTDATA_4, ids=['list', 'single value', 'empty', 'exception', 'get failure'] ) def test_cmakecache_get_list(value, correct_get, expected): file_data = f'DUMMY_NAME:{value}' with mock.patch('builtins.open', mock.mock_open(read_data=file_data)): cache = CMakeCache.from_file('dummy/path/CMakeCache.txt') with pytest.raises(expected) if \ isinstance(expected, type) and issubclass(expected, Exception) else \ nullcontext() as exception: res = cache.get_list('DUMMY_NAME') if \ correct_get else cache.get_list('ANOTHER_NAME') if exception is None: assert res == expected def test_cmakecache_dunders(): file_data = f'DUMMY_NAME:STRING=dummy value' with mock.patch('builtins.open', mock.mock_open(read_data=file_data)): cache = CMakeCache.from_file('dummy/path/CMakeCache.txt') assert len(list(cache.__iter__())) == 1 cache.__setitem__( 'ANOTHER_NAME', CMakeCacheEntry('ANOTHER_NAME', 'another value') ) assert cache.__contains__('ANOTHER_NAME') assert cache.__getitem__('ANOTHER_NAME') == 'another value' cache.__delitem__('ANOTHER_NAME') assert not cache.__contains__('ANOTHER_NAME') assert len(list(cache.__iter__())) == 1 with pytest.raises(TypeError): cache.__setitem__('WRONG_TYPE', 'Yet Another Dummy Value')