2019-02-15 13:19:05 +00:00
"""
Copyright ( c ) 2017 - 2019 ARM Limited . All rights reserved .
SPDX - License - Identifier : Apache - 2.0
Licensed under the Apache License , Version 2.0 ( the " License " ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : / / www . apache . org / licenses / LICENSE - 2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an " AS IS " BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
2019-03-19 22:36:02 +00:00
limitations
2019-02-15 13:19:05 +00:00
"""
2016-07-14 19:11:30 +00:00
import sys
import os
2016-09-27 22:40:18 +00:00
from string import printable
from copy import deepcopy
2016-10-03 20:15:08 +00:00
from mock import MagicMock , patch
2019-01-16 23:22:28 +00:00
from hypothesis import given , settings , HealthCheck
2017-03-07 17:41:56 +00:00
from hypothesis . strategies import text , lists , fixed_dictionaries , booleans
2016-07-14 19:11:30 +00:00
2019-02-19 10:38:53 +00:00
""" Tests for the toolchain sub-system """
2016-09-27 23:36:30 +00:00
ROOT = os . path . abspath ( os . path . join ( os . path . dirname ( __file__ ) , " .. " , " .. " ,
" .. " ) )
2016-07-14 19:11:30 +00:00
sys . path . insert ( 0 , ROOT )
2018-06-11 18:27:05 +00:00
from tools . toolchains import (
TOOLCHAIN_CLASSES ,
TOOLCHAIN_PATHS ,
mbedToolchain ,
)
2018-06-15 17:43:06 +00:00
from tools . resources import LEGACY_TOOLCHAIN_NAMES , Resources , FileType
2018-06-11 18:27:05 +00:00
from tools . targets import TARGET_MAP , set_targets_json_location
2018-05-01 14:10:59 +00:00
from tools . notifier . mock import MockNotifier
2016-07-14 19:11:30 +00:00
2018-05-31 21:32:31 +00:00
ALPHABET = [ char for char in printable if char not in [ u ' . ' , u ' / ' , u ' \\ ' ] ]
2016-09-27 22:40:18 +00:00
2019-02-19 16:48:21 +00:00
#Create a global test target
test_target_map = TARGET_MAP [ " K64F " ]
#We have to add ARMC5,UARM here to supported_toolchains, otherwise the creation of ARM class would fail as it won't find ARMC5 entry in supported_toolchains
#We also have to add uARM, cause, ARM_MICRO class would check for both uARM and ARMC5 in supported_toolchains(as ARM_MICRO represents ARMC5+Micro).
#And do this globally here so all tests can use this
test_target_map . supported_toolchains . append ( " ARMC5 " )
test_target_map . supported_toolchains . append ( " uARM " )
2018-06-26 14:18:23 +00:00
2018-06-26 14:15:01 +00:00
@patch ( ' tools.toolchains.arm.run_cmd ' )
2019-02-19 16:48:21 +00:00
def test_armc5_version_check ( _run_cmd ) :
2018-06-28 20:13:20 +00:00
set_targets_json_location ( )
2018-06-26 14:15:01 +00:00
_run_cmd . return_value = ( """
Product : ARM Compiler 5.06
Component : ARM Compiler 5.06 update 5 ( build 528 )
Tool : armcc [ 4 d3621 ]
""" , " " , 0)
notifier = MockNotifier ( )
2019-02-19 16:48:21 +00:00
target_map = TARGET_MAP [ " K64F " ]
#We have to add ARMC5 here to supported_toolchains, otherwise the creation of ARM class would fail as it wont find ARMC5 entry in supported_toolchains
target_map . supported_toolchains . append ( " ARMC5 " )
toolchain = TOOLCHAIN_CLASSES [ " ARM " ] ( target_map , notify = notifier )
2018-06-26 14:15:01 +00:00
toolchain . version_check ( )
assert notifier . messages == [ ]
_run_cmd . return_value = ( """
2018-06-28 15:58:52 +00:00
Product : MDK Professional 5.22
Component : ARM Compiler 5.06 update 5 ( build 528 )
Tool : armcc [ 4 d3621 ]
""" , " " , 0)
toolchain . version_check ( )
assert notifier . messages == [ ]
_run_cmd . return_value = ( """
2018-06-26 14:15:01 +00:00
Product : ARM Compiler
Component : ARM Compiler
Tool : armcc [ 4 d3621 ]
""" , " " , 0)
toolchain . version_check ( )
assert len ( notifier . messages ) == 1
2019-02-19 16:48:21 +00:00
@patch ( ' tools.toolchains.arm.run_cmd ' )
def test_armc6_version_check ( _run_cmd ) :
set_targets_json_location ( )
notifier = MockNotifier ( )
toolchain = TOOLCHAIN_CLASSES [ " ARMC6 " ] ( TARGET_MAP [ " K64F " ] , notify = notifier )
_run_cmd . return_value = ( """
Product : ARM Compiler 6.11 Professional
Component : ARM Compiler 6.11
Tool : armclang [ 5 d3b4200 ]
""" , " " , 0)
2019-03-19 22:36:02 +00:00
2019-02-19 16:48:21 +00:00
toolchain . version_check ( )
2019-03-19 22:36:28 +00:00
assert notifier . messages == [ ]
assert not toolchain . is_mbed_studio_armc6
_run_cmd . return_value = ( """
armclang : error : Failed to check out a license .
The provided license does not enable these tools .
Information about this error is available at : http : / / ds . arm . com / support / lic56 / m5
General licensing information is available at : http : / / ds . arm . com / support / licensing /
If you need further help , provide this complete error report to your supplier or license . support @arm.com .
- ARMLMD_LICENSE_FILE : unset
- LM_LICENSE_FILE : unset
- ARM_TOOL_VARIANT : unset
- ARM_PRODUCT_PATH : unset
- Product location : C : \MbedStudio \tools \ac6 \sw \mappings
- Toolchain location : C : \MbedStudio \tools \ac6 \bin
- Selected tool variant : product
- Checkout feature : mbed_armcompiler
- Feature version : 5.0201810
- Flex error code : - 5
Product : ARM Compiler 6.11 for Mbed Studio
Component : ARM Compiler 6.11
Tool : armclang [ 5 d3b3c00 ]
""" , " " , 0)
toolchain . version_check ( )
assert notifier . messages == [ ]
assert toolchain . is_mbed_studio_armc6
2018-06-26 14:18:23 +00:00
@patch ( ' tools.toolchains.iar.run_cmd ' )
def test_iar_version_check ( _run_cmd ) :
2018-06-28 20:13:20 +00:00
set_targets_json_location ( )
2018-06-26 14:18:23 +00:00
_run_cmd . return_value = ( """
2019-02-22 04:22:38 +00:00
IAR ANSI C / C + + Compiler V8 .32 .1 / LNX for ARM
2018-06-26 14:18:23 +00:00
""" , " " , 0)
notifier = MockNotifier ( )
toolchain = TOOLCHAIN_CLASSES [ " IAR " ] ( TARGET_MAP [ " K64F " ] , notify = notifier )
toolchain . version_check ( )
assert notifier . messages == [ ]
_run_cmd . return_value = ( """
IAR ANSI C / C + + Compiler V / LNX for ARM
""" , " " , 0)
toolchain . version_check ( )
assert len ( notifier . messages ) == 1
_run_cmd . return_value = ( """
IAR ANSI C / C + + Compiler V / 8.80 LNX for ARM
""" , " " , 0)
toolchain . version_check ( )
assert len ( notifier . messages ) == 2
2018-06-26 14:25:33 +00:00
@patch ( ' tools.toolchains.gcc.run_cmd ' )
def test_gcc_version_check ( _run_cmd ) :
2018-06-28 20:13:20 +00:00
set_targets_json_location ( )
2018-06-26 14:25:33 +00:00
_run_cmd . return_value = ( """
arm - none - eabi - gcc ( Arch Repository ) 6.4 .4
Copyright ( C ) 2018 Free Software Foundation , Inc .
This is free software ; see the source for copying conditions . There is NO
warranty ; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
""" , " " , 0)
notifier = MockNotifier ( )
toolchain = TOOLCHAIN_CLASSES [ " GCC_ARM " ] (
TARGET_MAP [ " K64F " ] , notify = notifier )
toolchain . version_check ( )
assert notifier . messages == [ ]
_run_cmd . return_value = ( """
arm - none - eabi - gcc ( Arch Repository ) 8.1 .0
Copyright ( C ) 2018 Free Software Foundation , Inc .
This is free software ; see the source for copying conditions . There is NO
warranty ; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
""" , " " , 0)
toolchain . version_check ( )
assert len ( notifier . messages ) == 1
_run_cmd . return_value = ( """
arm - none - eabi - gcc ( Arch Repository )
Copyright ( C ) 2018 Free Software Foundation , Inc .
This is free software ; see the source for copying conditions . There is NO
warranty ; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
""" , " " , 0)
toolchain . version_check ( )
assert len ( notifier . messages ) == 2
2016-09-27 22:40:18 +00:00
@given ( fixed_dictionaries ( {
' common ' : lists ( text ( ) ) ,
' c ' : lists ( text ( ) ) ,
' cxx ' : lists ( text ( ) ) ,
' asm ' : lists ( text ( ) ) ,
' ld ' : lists ( text ( ) ) } ) ,
2016-09-27 23:36:30 +00:00
lists ( text ( min_size = 1 , alphabet = ALPHABET ) , min_size = 1 ) )
2019-01-16 23:22:28 +00:00
@settings ( suppress_health_check = [ HealthCheck . too_slow ] )
2016-09-27 22:40:18 +00:00
def test_toolchain_profile_c ( profile , source_file ) :
2016-09-27 23:36:30 +00:00
""" Test that the appropriate profile parameters are passed to the
C compiler """
2016-09-27 22:40:18 +00:00
filename = deepcopy ( source_file )
filename [ - 1 ] + = " .c "
to_compile = os . path . join ( * filename )
2018-06-11 18:27:05 +00:00
set_targets_json_location ( )
2016-10-03 20:15:08 +00:00
with patch ( ' os.mkdir ' ) as _mkdir :
for _ , tc_class in TOOLCHAIN_CLASSES . items ( ) :
2019-02-19 16:48:21 +00:00
toolchain = tc_class ( test_target_map , build_profile = profile ,
2018-05-01 14:10:59 +00:00
notify = MockNotifier ( ) )
2016-10-03 20:15:08 +00:00
toolchain . inc_md5 = " "
toolchain . build_dir = " "
2017-06-05 20:45:51 +00:00
toolchain . config = MagicMock ( app_config_location = None )
2017-09-22 15:51:43 +00:00
for parameter in profile [ ' c ' ] + profile [ ' common ' ] :
assert any ( parameter in cmd for cmd in toolchain . cc ) , \
" Toolchain %s did not propagate arg %s " % ( toolchain . name ,
parameter )
2016-10-03 20:15:08 +00:00
compile_command = toolchain . compile_command ( to_compile ,
to_compile + " .o " , [ ] )
for parameter in profile [ ' c ' ] + profile [ ' common ' ] :
assert any ( parameter in cmd for cmd in compile_command ) , \
2017-09-22 15:51:43 +00:00
" Toolchain %s did not propagate arg %s " % ( toolchain . name ,
2016-10-03 20:15:08 +00:00
parameter )
2016-09-27 22:40:18 +00:00
@given ( fixed_dictionaries ( {
' common ' : lists ( text ( ) ) ,
' c ' : lists ( text ( ) ) ,
' cxx ' : lists ( text ( ) ) ,
' asm ' : lists ( text ( ) ) ,
' ld ' : lists ( text ( ) ) } ) ,
2016-09-27 23:36:30 +00:00
lists ( text ( min_size = 1 , alphabet = ALPHABET ) , min_size = 1 ) )
2019-01-16 23:22:28 +00:00
@settings ( suppress_health_check = [ HealthCheck . too_slow ] )
2016-09-27 22:40:18 +00:00
def test_toolchain_profile_cpp ( profile , source_file ) :
2016-09-27 23:36:30 +00:00
""" Test that the appropriate profile parameters are passed to the
C + + compiler """
2016-09-27 22:40:18 +00:00
filename = deepcopy ( source_file )
filename [ - 1 ] + = " .cpp "
to_compile = os . path . join ( * filename )
2016-10-03 20:15:08 +00:00
with patch ( ' os.mkdir ' ) as _mkdir :
for _ , tc_class in TOOLCHAIN_CLASSES . items ( ) :
2019-02-19 16:48:21 +00:00
toolchain = tc_class ( test_target_map , build_profile = profile ,
2018-05-01 14:10:59 +00:00
notify = MockNotifier ( ) )
2016-10-03 20:15:08 +00:00
toolchain . inc_md5 = " "
toolchain . build_dir = " "
2017-06-05 20:45:51 +00:00
toolchain . config = MagicMock ( app_config_location = None )
2017-09-22 15:51:43 +00:00
for parameter in profile [ ' cxx ' ] + profile [ ' common ' ] :
assert any ( parameter in cmd for cmd in toolchain . cppc ) , \
" Toolchain %s did not propagate arg %s " % ( toolchain . name ,
parameter )
2016-10-03 20:15:08 +00:00
compile_command = toolchain . compile_command ( to_compile ,
to_compile + " .o " , [ ] )
for parameter in profile [ ' cxx ' ] + profile [ ' common ' ] :
assert any ( parameter in cmd for cmd in compile_command ) , \
2017-09-22 15:51:43 +00:00
" Toolchain %s did not propagate arg %s " % ( toolchain . name ,
2016-10-03 20:15:08 +00:00
parameter )
2016-09-27 22:40:18 +00:00
@given ( fixed_dictionaries ( {
' common ' : lists ( text ( ) ) ,
' c ' : lists ( text ( ) ) ,
' cxx ' : lists ( text ( ) ) ,
' asm ' : lists ( text ( ) ) ,
' ld ' : lists ( text ( ) ) } ) ,
2016-09-27 23:36:30 +00:00
lists ( text ( min_size = 1 , alphabet = ALPHABET ) , min_size = 1 ) )
2019-01-16 23:22:28 +00:00
@settings ( suppress_health_check = [ HealthCheck . too_slow ] )
2016-09-27 22:40:18 +00:00
def test_toolchain_profile_asm ( profile , source_file ) :
2016-09-27 23:36:30 +00:00
""" Test that the appropriate profile parameters are passed to the
Assembler """
2016-09-27 22:40:18 +00:00
filename = deepcopy ( source_file )
filename [ - 1 ] + = " .s "
to_compile = os . path . join ( * filename )
2016-10-03 20:15:08 +00:00
with patch ( ' os.mkdir ' ) as _mkdir :
for _ , tc_class in TOOLCHAIN_CLASSES . items ( ) :
2019-02-19 16:48:21 +00:00
toolchain = tc_class ( test_target_map , build_profile = profile ,
2018-07-20 16:43:56 +00:00
notify = MockNotifier ( ) )
2016-10-03 20:15:08 +00:00
toolchain . inc_md5 = " "
toolchain . build_dir = " "
2018-06-20 14:45:57 +00:00
toolchain . config = MagicMock ( )
toolchain . config . get_config_data_macros . return_value = [ ]
2017-09-22 15:51:43 +00:00
for parameter in profile [ ' asm ' ] :
assert any ( parameter in cmd for cmd in toolchain . asm ) , \
" Toolchain %s did not propagate arg %s " % ( toolchain . name ,
parameter )
2016-10-03 20:15:08 +00:00
compile_command = toolchain . compile_command ( to_compile ,
to_compile + " .o " , [ ] )
if not compile_command :
assert compile_command , to_compile
for parameter in profile [ ' asm ' ] :
assert any ( parameter in cmd for cmd in compile_command ) , \
2017-09-22 15:51:43 +00:00
" Toolchain %s did not propagate arg %s " % ( toolchain . name ,
parameter )
for name , Class in TOOLCHAIN_CLASSES . items ( ) :
2019-02-19 16:48:21 +00:00
CLS = Class ( test_target_map , notify = MockNotifier ( ) )
2017-09-22 15:51:43 +00:00
assert name == CLS . name or name == LEGACY_TOOLCHAIN_NAMES [ CLS . name ]
@given ( fixed_dictionaries ( {
' common ' : lists ( text ( ) ) ,
' c ' : lists ( text ( ) ) ,
' cxx ' : lists ( text ( ) ) ,
' asm ' : lists ( text ( ) ) ,
' ld ' : lists ( text ( min_size = 1 ) ) } ) ,
lists ( text ( min_size = 1 , alphabet = ALPHABET ) , min_size = 1 ) )
2019-01-16 23:22:28 +00:00
@settings ( suppress_health_check = [ HealthCheck . too_slow ] )
2017-09-22 15:51:43 +00:00
def test_toolchain_profile_ld ( profile , source_file ) :
""" Test that the appropriate profile parameters are passed to the
Linker """
filename = deepcopy ( source_file )
filename [ - 1 ] + = " .o "
to_compile = os . path . join ( * filename )
with patch ( ' os.mkdir ' ) as _mkdir , \
patch ( ' tools.toolchains.mbedToolchain.default_cmd ' ) as _dflt_cmd :
for _ , tc_class in TOOLCHAIN_CLASSES . items ( ) :
2019-02-19 16:48:21 +00:00
toolchain = tc_class ( test_target_map , build_profile = profile ,
2018-05-01 14:10:59 +00:00
notify = MockNotifier ( ) )
2017-09-22 15:51:43 +00:00
toolchain . RESPONSE_FILES = False
toolchain . inc_md5 = " "
toolchain . build_dir = " "
for parameter in profile [ ' ld ' ] :
assert any ( parameter in cmd for cmd in toolchain . ld ) , \
" Toolchain %s did not propagate arg %s " % ( toolchain . name ,
parameter )
toolchain . link ( to_compile + " .elf " , [ to_compile ] , [ ] , [ ] , None )
compile_cmd = _dflt_cmd . call_args_list
if not compile_cmd :
assert compile_cmd , to_compile
for parameter in profile [ ' ld ' ] :
assert any ( parameter in cmd [ 0 ] [ 0 ] for cmd in compile_cmd ) , \
" Toolchain %s did not propagate arg %s " % ( toolchain . name ,
parameter )
2016-09-27 22:40:18 +00:00
2016-09-30 20:09:18 +00:00
for name , Class in TOOLCHAIN_CLASSES . items ( ) :
2019-02-19 16:48:21 +00:00
CLS = Class ( test_target_map , notify = MockNotifier ( ) )
2016-09-30 20:09:18 +00:00
assert name == CLS . name or name == LEGACY_TOOLCHAIN_NAMES [ CLS . name ]
@given ( lists ( text ( alphabet = ALPHABET , min_size = 1 ) , min_size = 1 ) )
def test_detect_duplicates ( filenames ) :
c_sources = [ os . path . join ( name , " dupe.c " ) for name in filenames ]
s_sources = [ os . path . join ( name , " dupe.s " ) for name in filenames ]
cpp_sources = [ os . path . join ( name , " dupe.cpp " ) for name in filenames ]
2018-05-01 14:10:59 +00:00
notify = MockNotifier ( )
2018-06-11 18:27:05 +00:00
res = Resources ( notify )
2018-06-15 17:43:06 +00:00
res . add_files_to_type ( FileType . C_SRC , c_sources )
res . add_files_to_type ( FileType . ASM_SRC , s_sources )
res . add_files_to_type ( FileType . CPP_SRC , cpp_sources )
2018-06-11 18:27:05 +00:00
assert res . detect_duplicates ( ) == 1 , \
2018-05-01 14:10:59 +00:00
" Not Enough duplicates found "
2016-09-30 20:09:18 +00:00
2018-05-01 14:10:59 +00:00
notification = notify . messages [ 0 ]
assert " dupe.o " in notification [ " message " ]
assert " dupe.s " in notification [ " message " ]
assert " dupe.c " in notification [ " message " ]
assert " dupe.cpp " in notification [ " message " ]
2017-03-07 17:41:56 +00:00
2018-05-31 21:32:31 +00:00
@given ( text ( alphabet = ALPHABET + [ os . sep ] , min_size = 1 ) )
2017-03-07 17:41:56 +00:00
@given ( booleans ( ) )
@given ( booleans ( ) )
@settings ( max_examples = 20 )
def test_path_specified_gcc ( gcc_loc , exists_at_loc , exists_in_path ) :
with patch ( ' tools.toolchains.gcc.exists ' ) as _exists :
with patch ( ' tools.toolchains.gcc.find_executable ' ) as _find :
_exists . return_value = exists_at_loc
_find . return_value = exists_in_path
TOOLCHAIN_PATHS [ ' GCC_ARM ' ] = gcc_loc
toolchain_class = TOOLCHAIN_CLASSES [ " GCC_ARM " ]
found_p = toolchain_class . check_executable ( )
assert found_p == ( exists_at_loc or exists_in_path )
if exists_at_loc :
assert TOOLCHAIN_PATHS [ ' GCC_ARM ' ] == gcc_loc
elif exists_in_path :
assert TOOLCHAIN_PATHS [ ' GCC_ARM ' ] == ' '