Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def test_current_stage(self):
"""
Go through the sequence of states emulating the real-life project lifecycle
"""
project = stm32pio.lib.Stm32pio(FIXTURE_PATH, parameters={'project': {'board': TEST_PROJECT_BOARD}})
for method, expected_stage in [(None, stm32pio.lib.ProjectStage.EMPTY),
('save_config', stm32pio.lib.ProjectStage.INITIALIZED),
('generate_code', stm32pio.lib.ProjectStage.GENERATED),
('pio_init', stm32pio.lib.ProjectStage.PIO_INITIALIZED),
('patch', stm32pio.lib.ProjectStage.PATCHED),
('build', stm32pio.lib.ProjectStage.BUILT),
('clean', stm32pio.lib.ProjectStage.EMPTY),
('pio_init', stm32pio.lib.ProjectStage.UNDEFINED)]:
if method is not None:
getattr(project, method)()
self.assertEqual(project.state.current_stage, expected_stage)
if expected_stage != stm32pio.lib.ProjectStage.UNDEFINED:
self.assertTrue(project.state.is_consistent)
else:
# Should be UNDEFINED when the project is messed up (pio_init() after clean())
self.assertFalse(project.state.is_consistent)
def test_rebase_project(self):
"""
Test the portability of projects: they should stay totally valid after moving to another path (same as renaming
the parent part of the path). If we will not meet any exceptions, we should consider the test passed
"""
project_before = stm32pio.lib.Stm32pio(FIXTURE_PATH, parameters={'project': {'board': TEST_PROJECT_BOARD}})
project_before.save_config()
new_path = f'{project_before.path}-moved'
shutil.move(str(project_before.path), new_path)
project_after = stm32pio.lib.Stm32pio(new_path, parameters={'project': {'board': TEST_PROJECT_BOARD}})
self.assertEqual(project_after.generate_code(), 0)
self.assertEqual(project_after.pio_init(), 0)
self.assertEqual(project_after.patch(), None)
self.assertEqual(project_after.build(), 0)
def test_generate_code(self):
"""
Check whether files and folders have been created (by STM32CubeMX)
"""
project = stm32pio.lib.Stm32pio(FIXTURE_PATH, parameters={'project': {'board': TEST_PROJECT_BOARD}})
project.generate_code()
# Assuming that the presence of these files indicating a success
files_should_be_present = ['Src/main.c', 'Inc/main.h']
for file in files_should_be_present:
with self.subTest(msg=f"{file} hasn't been created"):
self.assertEqual(FIXTURE_PATH.joinpath(file).is_file(), True)
def test_patch(self):
"""
Check that new parameters were added, modified were updated and existing parameters didn't gone. Also, check for
unnecessary folders deletion
"""
project = stm32pio.lib.Stm32pio(FIXTURE_PATH)
test_content = inspect.cleandoc('''
; This is a test config .ini file
; with a comment. It emulates a real
; platformio.ini file
[platformio]
include_dir = this s;789hould be replaced
; there should appear a new parameter
test_key3 = this should be preserved
[test_section]
test_key1 = test_value1
test_key2 = 123
''') + '\n'
FIXTURE_PATH.joinpath('platformio.ini').write_text(test_content)
return_code = stm32pio.app.main(sys_argv=['status', '-d', str(FIXTURE_PATH)])
self.assertEqual(return_code, 0, msg="Non-zero return code")
matches_counter = 0
last_stage_pos = -1
for stage in stm32pio.lib.ProjectStage:
if stage != stm32pio.lib.ProjectStage.UNDEFINED:
match = re.search(r"^((\[ \])|(\[\*\])) {2}" + str(stage) + '$', buffer_stdout.getvalue(), re.MULTILINE)
self.assertTrue(match, msg="Status information was not found on STDOUT")
if match:
matches_counter += 1
self.assertGreater(match.start(), last_stage_pos, msg="The order of stages is messed up")
last_stage_pos = match.start()
self.assertEqual(matches_counter, len(stm32pio.lib.ProjectStage) - 1)
def test_verbose(self):
"""
Capture the full output. Check for both 'DEBUG' logging messages and STM32CubeMX CLI output. Verbose logs format
should match such a regex:
^(?=(DEBUG|INFO|WARNING|ERROR|CRITICAL) {0,4})(?=.{8} (?=(build|pio_init|...) {0,26})(?=.{26} [^ ]))
"""
# inspect.getmembers() is great but it triggers class properties to execute leading to the unwanted code
# execution
methods = dir(stm32pio.lib.Stm32pio) + ['main']
buffer_stdout, buffer_stderr = io.StringIO(), io.StringIO()
with contextlib.redirect_stdout(buffer_stdout), contextlib.redirect_stderr(buffer_stderr):
return_code = stm32pio.app.main(sys_argv=['-v', 'new', '-d', str(FIXTURE_PATH), '-b', TEST_PROJECT_BOARD])
self.assertEqual(return_code, 0, msg="Non-zero return code")
# stderr and not stdout contains the actual output (by default for the logging module)
self.assertEqual(len(buffer_stdout.getvalue()), 0,
msg="Process has printed something directly into STDOUT bypassing logging")
self.assertIn('DEBUG', buffer_stderr.getvalue(), msg="Verbose logging output hasn't been enabled on STDERR")
# Inject all methods' names in the regex. Inject the width of field in a log format string
regex = re.compile("^(?=(DEBUG) {0,4})(?=.{8} (?=(" + '|'.join(methods) + ") {0," +
str(stm32pio.settings.log_fieldwidth_function) + "})(?=.{" +
str(stm32pio.settings.log_fieldwidth_function) + "} [^ ]))", flags=re.MULTILINE)
self.assertGreaterEqual(len(re.findall(regex, buffer_stderr.getvalue())), 1,
args = parse_args(sys_argv)
if args is not None and args.subcommand == 'gui':
import stm32pio_gui.app
gui_args = [arg for arg in sys_argv if arg != 'gui']
return stm32pio_gui.app.main(sys_argv=gui_args)
elif args is not None and args.subcommand is not None:
logger = setup_logging(args_verbose_counter=args.verbose, dummy=not should_setup_logging)
else:
print("\nNo arguments were given, exiting...")
return 0
# Main routine
try:
if args.subcommand == 'init':
project = stm32pio.lib.Stm32pio(args.path, parameters={'project': {'board': args.board}},
instance_options={'save_on_destruction': True})
if not args.board:
logger.warning("PlatformIO board identifier is not specified, it will be needed on PlatformIO project "
"creation. Type 'pio boards' or go to https://platformio.org to find an appropriate "
"identifier")
logger.info("project has been initialized. You can now edit stm32pio.ini config file")
if args.editor:
project.start_editor(args.editor)
elif args.subcommand == 'new':
project = stm32pio.lib.Stm32pio(args.path, parameters={'project': {'board': args.board}},
instance_options={'save_on_destruction': True})
if project.config.get('project', 'board') == '':
raise Exception("PlatformIO board identifier is not specified, it is needed for PlatformIO project "
"creation. Type 'pio boards' or go to https://platformio.org to find an appropriate "
"identifier")
# (stm32pio.lib.ProjectStage.GENERATED, True),
# (stm32pio.lib.ProjectStage.PIO_INITIALIZED, True),
# (stm32pio.lib.ProjectStage.PATCHED, False),
# (stm32pio.lib.ProjectStage.BUILT, True),
# ])
# logger = logging.getLogger('stm32pio') # the root (relatively to the possible outer scope) logger instance
# handler = logging.StreamHandler()
# logger.addHandler(handler)
# special_formatters = {'subprocess': logging.Formatter('%(message)s')}
# logger.setLevel(logging.DEBUG)
# handler.setFormatter(stm32pio.util.DispatchingFormatter(
# f"%(levelname)-8s %(funcName)-{stm32pio.settings.log_fieldwidth_function}s %(message)s",
# special=special_formatters))
p = stm32pio.lib.Stm32pio('/Users/chufyrev/Documents/GitHub/stm32pio/stm32pio-test-project',
parameters={ 'board': 'nucleo_f031k6' }, save_on_destruction=False)
print(p.state)
print()