diff --git a/tests/test_plot/test_misc_2.py b/tests/test_plot/test_misc_2.py index 2013f9fe..2f8e709d 100644 --- a/tests/test_plot/test_misc_2.py +++ b/tests/test_plot/test_misc_2.py @@ -3,7 +3,7 @@ import sys import pytest import coverage import logging -from subprocess import CalledProcessError +import subprocess # Look for the 'utils' module from where the script is running prev_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) if prev_dir not in sys.path: @@ -18,7 +18,7 @@ from kibot.pre_base import BasePreFlight from kibot.gs import GS from kibot.kiplot import load_actions, _import from kibot.registrable import RegOutput, RegFilter -from kibot.misc import (MISSING_TOOL, WRONG_INSTALL, BOM_ERROR) +from kibot.misc import (MISSING_TOOL, WRONG_INSTALL, BOM_ERROR, DRC_ERROR, ERC_ERROR) from kibot.bom.columnlist import ColumnList @@ -30,6 +30,7 @@ mocked_check_output_retOK = '' # Important note: # - We can't load the plug-ins twice, the import fails. # - Once we patched them using monkey patch the patch isn't reverted unless we load them again. +# I don't know the real reason, may be related to the way we load plug-ins. # For this reason this patch is used for more than one case. def mocked_check_output(cmd, stderr=None): logging.debug('mocked_check_output called') @@ -38,32 +39,37 @@ def mocked_check_output(cmd, stderr=None): else: if mocked_check_output_retOK: return mocked_check_output_retOK - e = CalledProcessError(10, 'rar') + e = subprocess.CalledProcessError(10, 'rar') e.output = b'THE_ERROR' raise e +def mocked_call(cmd): + logging.debug('Forcing fail on '+str(cmd)) + return 5 + + +def patch_functions(m): + m.setattr("subprocess.check_output", mocked_check_output) + m.setattr('kibot.kiplot.exec_with_retry', mocked_call) + + def run_compress(ctx, test_import_fail=False): - # Start coverage - cov.load() - cov.start() - # Load the plug-ins - load_actions() - # Create a compress object with the dummy file as source - out = RegOutput.get_class_for('compress')() - out.set_tree({'options': {'format': 'RAR', 'files': [{'source': ctx.get_out_path('*')}]}}) - out.config() - # Setup the GS output dir, needed for the output path - GS.out_dir = '.' - # Run the compression and catch the error - with pytest.raises(SystemExit) as pytest_wrapped_e: - if test_import_fail: - _import('out_bogus', os.path.abspath(os.path.join(os.path.dirname(__file__), 'fake_plugin/out_bogus.py'))) - else: - out.run('') - # Stop coverage - cov.stop() - cov.save() + with context.cover_it(cov): + # Load the plug-ins + load_actions() + # Create a compress object with the dummy file as source + out = RegOutput.get_class_for('compress')() + out.set_tree({'options': {'format': 'RAR', 'files': [{'source': ctx.get_out_path('*')}]}}) + out.config() + # Setup the GS output dir, needed for the output path + GS.out_dir = '.' + # Run the compression and catch the error + with pytest.raises(SystemExit) as pytest_wrapped_e: + if test_import_fail: + _import('out_bogus', os.path.abspath(os.path.join(os.path.dirname(__file__), 'fake_plugin/out_bogus.py'))) + else: + out.run('') return pytest_wrapped_e @@ -76,7 +82,7 @@ def test_no_rar(test_dir, caplog, monkeypatch): ctx.create_dummy_out_file('Test.txt') # We will patch subprocess.check_output to make rar fail with monkeypatch.context() as m: - m.setattr("subprocess.check_output", mocked_check_output) + patch_functions(m) pytest_wrapped_e = run_compress(ctx) # Check we exited because rar isn't installed assert pytest_wrapped_e.type == SystemExit @@ -93,7 +99,7 @@ def test_rar_fail(test_dir, caplog, monkeypatch): ctx.create_dummy_out_file('Test.txt') # We will patch subprocess.check_output to make rar fail with monkeypatch.context() as m: - m.setattr("subprocess.check_output", mocked_check_output) + patch_functions(m) pytest_wrapped_e = run_compress(ctx) pytest_wrapped_e2 = run_compress(ctx, test_import_fail=True) # Check we exited because rar isn't installed @@ -129,15 +135,10 @@ def test_no_get_targets(caplog): # Also check the dependencies fallback GS.sch = None GS.sch_file = 'fake' - # Start coverage - cov.load() - cov.start() - test.get_targets('') - files = test.get_dependencies() - files_pre = test_pre.get_dependencies() - # Stop coverage - cov.stop() - cov.save() + with context.cover_it(cov): + test.get_targets('') + files = test.get_dependencies() + files_pre = test_pre.get_dependencies() assert "Output 'Fake' (dummy) [none] doesn't implement get_targets(), plese report it" in caplog.text assert files == [GS.sch_file] assert files_pre == [GS.sch_file] @@ -150,23 +151,18 @@ def test_ibom_parse_fail(test_dir, caplog, monkeypatch): mocked_check_output_retOK = b'ERROR Parsing failed' # We will patch subprocess.check_output to make ibom fail with monkeypatch.context() as m: - m.setattr("subprocess.check_output", mocked_check_output) - # Start coverage - cov.load() - cov.start() - # Load the plug-ins - load_actions() - # Create an ibom object - out = RegOutput.get_class_for('ibom')() - out.set_tree({}) - out.config() - # Setup the GS output dir, needed for the output path - #GS.out_dir = '.' - with pytest.raises(SystemExit) as pytest_wrapped_e: - out.run('') - # Stop coverage - cov.stop() - cov.save() + patch_functions(m) + with context.cover_it(cov): + # Load the plug-ins + load_actions() + # Create an ibom object + out = RegOutput.get_class_for('ibom')() + out.set_tree({}) + out.config() + # Setup the GS output dir, needed for the output path + #GS.out_dir = '.' + with pytest.raises(SystemExit) as pytest_wrapped_e: + out.run('') assert pytest_wrapped_e.type == SystemExit assert pytest_wrapped_e.value.code == BOM_ERROR # logging.debug(caplog.text) @@ -175,36 +171,49 @@ def test_ibom_parse_fail(test_dir, caplog, monkeypatch): def test_var_rename_no_variant(): - # Start coverage - cov.load() - cov.start() - # Load the plug-ins - load_actions() - # Create an ibom object - filter = RegFilter.get_class_for('var_rename')() - GS.variant = None - # Should just return - filter.filter(None) - # Stop coverage - cov.stop() - cov.save() + with context.cover_it(cov): + # Load the plug-ins + load_actions() + # Create an ibom object + filter = RegFilter.get_class_for('var_rename')() + GS.variant = None + # Should just return + filter.filter(None) def test_bom_no_sch(): - # Start coverage - cov.load() - cov.start() - # Load the plug-ins - load_actions() - # Create an ibom object - GS.sch = None - out = RegOutput.get_class_for('bom')() - columns = out.options._get_columns() - assert columns == ColumnList.COLUMNS_DEFAULT - out = RegOutput.get_class_for('kibom')() - options = out.options() - columns = options.conf._get_columns() - assert columns == ColumnList.COLUMNS_DEFAULT - # Stop coverage - cov.stop() - cov.save() + with context.cover_it(cov): + # Load the plug-ins + load_actions() + # Create an ibom object + GS.sch = None + out = RegOutput.get_class_for('bom')() + columns = out.options._get_columns() + assert columns == ColumnList.COLUMNS_DEFAULT + out = RegOutput.get_class_for('kibom')() + options = out.options() + columns = options.conf._get_columns() + assert columns == ColumnList.COLUMNS_DEFAULT + + +def test_pre_xrc_fail(test_dir, caplog, monkeypatch): + ctx = context.TestContext(test_dir, 'test_pre_xrc_fail', 'test_v5', 'empty_zip', '') + with monkeypatch.context() as m: + patch_functions(m) + with context.cover_it(cov): + load_actions() + GS.set_pcb(ctx.board_file) + sch = ctx.board_file + GS.set_sch(sch.replace('.kicad_pcb', '.sch')) + GS.out_dir = test_dir + pre_drc = BasePreFlight.get_class_for('run_drc')('run_drc', True) + pre_erc = BasePreFlight.get_class_for('run_erc')('run_erc', True) + with pytest.raises(SystemExit) as e1: + pre_drc.run() + with pytest.raises(SystemExit) as e2: + pre_erc.run() + assert e1.type == SystemExit + assert e1.value.code == DRC_ERROR + assert e2.type == SystemExit + assert e2.value.code == ERC_ERROR + ctx.clean_up() diff --git a/tests/utils/context.py b/tests/utils/context.py index 06902925..53c725e1 100644 --- a/tests/utils/context.py +++ b/tests/utils/context.py @@ -6,6 +6,7 @@ import logging import subprocess import re import csv +from contextlib import contextmanager from glob import glob from pty import openpty import xml.etree.ElementTree as ET @@ -71,6 +72,17 @@ def usable_cmd(cmd): return ' '.join(cmd) +@contextmanager +def cover_it(cov): + # Start coverage + cov.load() + cov.start() + yield + # Stop coverage + cov.stop() + cov.save() + + class TestContext(object): def __init__(self, test_dir, test_name, board_name, yaml_name, sub_dir, yaml_compressed=False, add_cfg_kmajor=False):