diff --git a/pytest-embedded-idf/tests/test_idf.py b/pytest-embedded-idf/tests/test_idf.py index f16d34ff..8c01292f 100644 --- a/pytest-embedded-idf/tests/test_idf.py +++ b/pytest-embedded-idf/tests/test_idf.py @@ -35,6 +35,63 @@ def test_idf_serial_flash(dut): result.assert_outcomes(passed=1) +def test_expect_no_matching(testdir): + testdir.makepyfile(""" + import pexpect + import pytest + import re + + def test_no_matching_list(dut): + dut.expect('world!', not_matching=[re.compile("Hell"), "Hello"]) + + def test_no_matching_word(dut): + dut.expect('Restarting', not_matching="Hello world!") + + def test_no_matching_word_pass(dut): + dut.expect('Restarting', not_matching="Hello world!333") + + def test_no_matching_word_pass_rest(dut): + dut.expect('Hello world', not_matching="Restarting") + + """) + + result = testdir.runpytest( + '-s', + '--embedded-services', 'esp,idf', + '--app-path', os.path.join(testdir.tmpdir, 'hello_world_esp32'), + ) + + result.assert_outcomes(passed=2, failed=2) + + +def test_expect_exact_no_matching(testdir): + testdir.makepyfile(""" + import pexpect + import pytest + + def test_no_matching_list(dut): + dut.expect_exact('world!', not_matching=["Hell1", "Hello"]) + + def test_no_matching_word(dut): + dut.expect_exact('Restarting', not_matching="Hello world!") + + def test_no_matching_word_pass(dut): + dut.expect_exact('Restarting', not_matching="Hello world!333") + + def test_no_matching_word_pass_rest(dut): + dut.expect_exact('Hello world', not_matching="Restarting") + + """) + + result = testdir.runpytest( + '-s', + '--embedded-services', 'esp,idf', + '--app-path', os.path.join(testdir.tmpdir, 'hello_world_esp32'), + ) + + result.assert_outcomes(passed=2, failed=2) + + def test_idf_serial_flash_with_erase_nvs(testdir): testdir.makepyfile(""" import pexpect diff --git a/pytest-embedded/pytest_embedded/dut.py b/pytest-embedded/pytest_embedded/dut.py index 5e618e2d..13c8669d 100644 --- a/pytest-embedded/pytest_embedded/dut.py +++ b/pytest-embedded/pytest_embedded/dut.py @@ -2,6 +2,7 @@ import logging import multiprocessing import os.path +import re from typing import AnyStr, Callable, List, Match, Optional, Union import pexpect @@ -66,7 +67,7 @@ def write(self, s: AnyStr) -> None: def _pexpect_func(func) -> Callable[..., Union[Match, AnyStr]]: # noqa @functools.wraps(func) # noqa def wrapper( - self, pattern, *args, expect_all: bool = False, **kwargs + self, pattern, *args, expect_all: bool = False, not_matching: List[Union[str, re.Pattern]] = (), **kwargs ) -> Union[Union[Match, AnyStr], List[Union[Match, AnyStr]]]: patterns = to_list(pattern) res = [] @@ -80,11 +81,20 @@ def wrapper( f'Please check the full log here: {self.logfile}' ) raise e.__class__(debug_str) from e + + if self.pexpect_proc.match in [pexpect.EOF, pexpect.TIMEOUT]: + res.append(self.pexpect_proc.before.rstrip()) else: - if self.pexpect_proc.match in [pexpect.EOF, pexpect.TIMEOUT]: - res.append(self.pexpect_proc.before.rstrip()) - else: - res.append(self.pexpect_proc.match) + res.append(self.pexpect_proc.match) + + for nm_pattern in to_list(not_matching): + if isinstance(nm_pattern, str): + nm_pattern = re.compile(nm_pattern.encode()) + if isinstance(nm_pattern.pattern, str): + nm_pattern = re.compile(nm_pattern.pattern.encode()) + + if nm_pattern.search(self.pexpect_proc.before): + raise ValueError(f'The pattern {nm_pattern} should not have been matched.') if expect_all: patterns.pop(index) @@ -110,6 +120,7 @@ def expect(self, pattern, **kwargs) -> Match: # noqa timeout (float): would raise `pexpect.TIMEOUT` exception when pattern is not matched after timeout expect_all (bool): need to match all specified patterns if this flag is `True`. Otherwise match any of them could pass + not_matching: string, or compiled regex, or a list of string and compiled regex. Returns: `AnyStr` or `re.Match` @@ -131,6 +142,7 @@ def expect_exact(self, pattern, **kwargs) -> Match: # noqa timeout (float): would raise `pexpect.TIMEOUT` exception when pattern is not matched after timeout expect_all (bool): need to match all specified patterns if this flag is `True`. Otherwise match any of them could pass + not_matching: string, or compiled regex, or a list of string and compiled regex. Returns: `AnyStr` or `re.Match`