diff --git a/docs/cli.md b/docs/cli.md index 6bf3976..b8a6fc2 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -74,7 +74,7 @@ When the flag **--adi-hw-map** is used the provided map from [plugin itself is u If the flag **--hw=** is used the hardware map is ignored and the provided URI is defined as that hardware. This is handy if you do not want to create a custom map or are debugging. Note that **--hw** is only applicable when **--uri** is also used. -A hardware entry may also carry a `blacklist:` section used to exclude specific devices, channels, or attributes from **--iio-coverage** tracking. See [Blacklisting devices, channels, and attributes](#blacklisting-devices-channels-and-attributes). +A hardware entry may also carry an `ignore:` section used to exclude specific devices, channels, or attributes from **--iio-coverage** tracking. See [Ignoring devices, channels, and attributes](#ignoring-devices-channels-and-attributes). ## Telemetry @@ -106,14 +106,14 @@ Both land in the directory named by **--iio-coverage-folder** (default per-context attribute map to stdout, or **--iio-coverage-debug-props** to include debug attributes in the tally. -### Blacklisting devices, channels, and attributes +### Ignoring devices, channels, and attributes Some attributes are noise for coverage purposes — diagnostic devices, write-only or unsupported attributes, or whole families no test could reasonably exercise. These drag down the reported percentage without adding signal. To exclude them, -add a `blacklist:` section to the relevant hardware entry in the +add an `ignore:` section to the relevant hardware entry in the [hardware map](#hardware-maps) (works with both **--adi-hw-map** and -**--custom-hw-map**). Blacklisted items are removed entirely: they are not +**--custom-hw-map**). Ignored items are removed entirely: they are not counted when accessed and do not appear in the coverage denominator. ``` yaml @@ -122,7 +122,7 @@ pluto: - cf-ad9361-lpc,2 - emulate: - filename: pluto.xml - - blacklist: + - ignore: devices: # whole devices (all channels/attrs) - xadc - "cf-*" # glob: every capture device @@ -147,6 +147,6 @@ pluto: Every string field is matched as a case-sensitive glob (Python's `fnmatch.fnmatchcase`), so `*` and `?` wildcards are supported, and an omitted optional field matches anything. Debug attributes (**--iio-coverage-debug-props**) -honor whole-`devices` blacklisting only. +honor whole-`devices` ignoring only. For a worked example see [Scenario: attribute coverage](fixtures.md#scenario-attribute-coverage). diff --git a/pytest_libiio/coverage.py b/pytest_libiio/coverage.py index 1ad614f..a558478 100644 --- a/pytest_libiio/coverage.py +++ b/pytest_libiio/coverage.py @@ -15,12 +15,12 @@ def _match(pattern, value): return fnmatch.fnmatchcase(value, pattern) -class Blacklist: +class IgnoreList: """Match devices, channels, and attributes to exclude from coverage. - Built from a per-hardware ``blacklist`` mapping in the hardware map YAML:: + Built from a per-hardware ``ignore`` mapping in the hardware map YAML:: - blacklist: + ignore: devices: [xadc, "cf-*"] channels: - {device: ad9361-phy, id: voltage0} @@ -38,13 +38,13 @@ def __init__(self, spec): self._channels = list(spec.get("channels") or []) self._attributes = list(spec.get("attributes") or []) - def device_blacklisted(self, device): + def device_ignored(self, device): """True if the whole device is excluded.""" return any(_match(pat, device) for pat in self._devices) - def channel_blacklisted(self, device, channel, direction): + def channel_ignored(self, device, channel, direction): """True if the whole channel (and all its attrs) is excluded.""" - if self.device_blacklisted(device): + if self.device_ignored(device): return True for entry in self._channels: if ( @@ -55,14 +55,14 @@ def channel_blacklisted(self, device, channel, direction): return True return False - def attr_blacklisted(self, device, channel, attr, direction): + def attr_ignored(self, device, channel, attr, direction): """True if a single attribute is excluded. ``channel`` is ``None`` for device-level attributes; otherwise the attribute belongs to the named channel. """ if channel is None: - if self.device_blacklisted(device): + if self.device_ignored(device): return True for entry in self._attributes: if "channel" in entry: @@ -73,7 +73,7 @@ def attr_blacklisted(self, device, channel, attr, direction): return True return False - if self.channel_blacklisted(device, channel, direction): + if self.channel_ignored(device, channel, direction): return True for entry in self._attributes: if "channel" not in entry: @@ -96,9 +96,9 @@ def __init__(self): self.track_context_props = False self.track_debug_props = False self.results_folder = "iio_coverage_results" - # Per-hardware blacklist specs, keyed by hardware name. Populated from + # Per-hardware ignore specs, keyed by hardware name. Populated from # the hardware map; consulted in add_instance. - self.blacklists = {} + self.ignores = {} def do_monkey_patch(self): """Apply monkey patch to iio.py.""" @@ -120,7 +120,7 @@ def add_instance(self, name, uri): uri, self.track_context_props, self.track_debug_props, - blacklist=self.blacklists.get(name), + ignore=self.ignores.get(name), ) else: raise Exception(f"{name} already in tracker list") @@ -144,7 +144,7 @@ def __init__( track_context_props=False, track_debug_props=False, results_folder=None, - blacklist=None, + ignore=None, ): self.name = name self.context_attr_reads_writes = {} @@ -156,7 +156,7 @@ def __init__( self.track_context_props = track_context_props self.track_debug_props = track_debug_props self.results_folder = results_folder or "iio_coverage_results" - self.blacklist = Blacklist(blacklist) if blacklist else None + self.ignore = IgnoreList(ignore) if ignore else None self.build_context_map() def reset(self): @@ -169,24 +169,24 @@ def reset(self): def build_context_map(self): """Build a map of context attributes. - Entries excluded by ``self.blacklist`` are omitted entirely so they + Entries excluded by ``self.ignore`` are omitted entirely so they never count toward coverage denominators. """ - bl = self.blacklist + ig = self.ignore if self.track_context_props: self.context_attr_reads_writes = {attr: 0 for attr in self.ctx.attrs} for dev in self.ctx.devices: - if bl and bl.device_blacklisted(dev.name): + if ig and ig.device_ignored(dev.name): continue self.device_attr_reads_writes[dev.name] = { attr: 0 for attr in dev.attrs - if not (bl and bl.attr_blacklisted(dev.name, None, attr, None)) + if not (ig and ig.attr_ignored(dev.name, None, attr, None)) } for inout in ["input", "output"]: for channel in dev.channels: inout = "output" if channel.output else "input" - if bl and bl.channel_blacklisted(dev.name, channel.id, inout): + if ig and ig.channel_ignored(dev.name, channel.id, inout): continue if dev.name not in self.channel_attr_reads_writes: self.channel_attr_reads_writes[dev.name] = {} @@ -196,8 +196,7 @@ def build_context_map(self): attr: 0 for attr in channel.attrs if not ( - bl - and bl.attr_blacklisted(dev.name, channel.id, attr, inout) + ig and ig.attr_ignored(dev.name, channel.id, attr, inout) ) } if self.track_debug_props: diff --git a/pytest_libiio/mkpatch.py b/pytest_libiio/mkpatch.py index 48f5e8c..32ee0a5 100644 --- a/pytest_libiio/mkpatch.py +++ b/pytest_libiio/mkpatch.py @@ -37,17 +37,15 @@ def _read(self): device_name = name_raw.decode("ascii") if name_raw is not None else None tracker = _get_tracker() - bl = getattr(tracker, "blacklist", None) + ig = getattr(tracker, "ignore", None) if channel_name and device_name: inout = "output" if output else "input" - if not ( - bl and bl.attr_blacklisted(device_name, channel_name, attr_name, inout) - ): + if not (ig and ig.attr_ignored(device_name, channel_name, attr_name, inout)): tracker.channel_attr_reads_writes[device_name][inout][channel_name][ attr_name ] += 1 elif device_name: - if not (bl and bl.attr_blacklisted(device_name, None, attr_name, None)): + if not (ig and ig.attr_ignored(device_name, None, attr_name, None)): tracker.device_attr_reads_writes[device_name][attr_name] += 1 else: tracker.context_attr_reads_writes[attr_name] += 1 @@ -79,17 +77,15 @@ def _write(self, value): device_name = name_raw.decode("ascii") if name_raw is not None else None tracker = _get_tracker() - bl = getattr(tracker, "blacklist", None) + ig = getattr(tracker, "ignore", None) if channel_name and device_name: inout = "output" if output else "input" - if not ( - bl and bl.attr_blacklisted(device_name, channel_name, attr_name, inout) - ): + if not (ig and ig.attr_ignored(device_name, channel_name, attr_name, inout)): tracker.channel_attr_reads_writes[device_name][inout][channel_name][ attr_name ] += 1 elif device_name: - if not (bl and bl.attr_blacklisted(device_name, None, attr_name, None)): + if not (ig and ig.attr_ignored(device_name, None, attr_name, None)): tracker.device_attr_reads_writes[device_name][attr_name] += 1 else: tracker.context_attr_reads_writes[attr_name] += 1 diff --git a/pytest_libiio/plugin.py b/pytest_libiio/plugin.py index e26ec4c..b7175b3 100644 --- a/pytest_libiio/plugin.py +++ b/pytest_libiio/plugin.py @@ -132,23 +132,23 @@ def get_filename(map, hw): return fn, dd -def extract_blacklists(map): - """Return ``{hardware_name: blacklist_spec}`` for entries that define one. +def extract_ignores(map): + """Return ``{hardware_name: ignore_spec}`` for entries that define one. - The blacklist is a ``blacklist:`` dict item inside a hardware entry's list, + The ignore spec is an ``ignore:`` dict item inside a hardware entry's list, alongside ``emulate:``/``ctx_attr:``. Used to exclude devices, channels, or attributes from ``--iio-coverage`` tracking. """ - blacklists = {} + ignores = {} if not map: - return blacklists + return ignores for hw, items in map.items(): if not isinstance(items, list): continue for item in items: - if isinstance(item, dict) and "blacklist" in item: - blacklists[hw] = item["blacklist"] - return blacklists + if isinstance(item, dict) and "ignore" in item: + ignores[hw] = item["ignore"] + return ignores def handle_iio_emu(ctx, request, _iio_emu): @@ -344,12 +344,12 @@ class Object(object): tracker.track_debug_props = bool( session.config.getoption("--iio-coverage-debug-props") ) - # Load per-hardware coverage blacklists from the hardware map, if one is + # Load per-hardware coverage ignores from the hardware map, if one is # in use. get_hw_map only reads config options, so the session stands in # for a request here. hw_map = get_hw_map(session) if hw_map: - tracker.blacklists = extract_blacklists(hw_map) + tracker.ignores = extract_ignores(hw_map) print("IIO coverage tracking enabled") else: session.config.pytest_libiio = Object() diff --git a/tests/test_coverage_unit.py b/tests/test_coverage_unit.py index 3492be2..c9c7fce 100644 --- a/tests/test_coverage_unit.py +++ b/tests/test_coverage_unit.py @@ -41,30 +41,30 @@ def __init__(self): ] -def test_blacklist_empty_spec_matches_nothing(): - bl = coverage.Blacklist(None) - assert not bl.device_blacklisted("dev0") - assert not bl.channel_blacklisted("dev0", "voltage0", "input") - assert not bl.attr_blacklisted("dev0", None, "dev_a", None) - assert not bl.attr_blacklisted("dev0", "voltage0", "scale", "input") - - bl = coverage.Blacklist({}) - assert not bl.device_blacklisted("dev0") - - -def test_blacklist_device_exact_and_glob(): - bl = coverage.Blacklist({"devices": ["xadc", "cf-*"]}) - assert bl.device_blacklisted("xadc") - assert bl.device_blacklisted("cf-ad9361-lpc") - assert not bl.device_blacklisted("ad9361-phy") - # A blacklisted device cascades to its attrs and channels. - assert bl.attr_blacklisted("xadc", None, "in_temp0_input", None) - assert bl.attr_blacklisted("cf-ad9361-lpc", "voltage0", "scale", "input") - assert bl.channel_blacklisted("cf-ad9361-lpc", "voltage0", "input") - - -def test_blacklist_channel_with_and_without_direction(): - bl = coverage.Blacklist( +def test_ignore_empty_spec_matches_nothing(): + bl = coverage.IgnoreList(None) + assert not bl.device_ignored("dev0") + assert not bl.channel_ignored("dev0", "voltage0", "input") + assert not bl.attr_ignored("dev0", None, "dev_a", None) + assert not bl.attr_ignored("dev0", "voltage0", "scale", "input") + + bl = coverage.IgnoreList({}) + assert not bl.device_ignored("dev0") + + +def test_ignore_device_exact_and_glob(): + bl = coverage.IgnoreList({"devices": ["xadc", "cf-*"]}) + assert bl.device_ignored("xadc") + assert bl.device_ignored("cf-ad9361-lpc") + assert not bl.device_ignored("ad9361-phy") + # An ignored device cascades to its attrs and channels. + assert bl.attr_ignored("xadc", None, "in_temp0_input", None) + assert bl.attr_ignored("cf-ad9361-lpc", "voltage0", "scale", "input") + assert bl.channel_ignored("cf-ad9361-lpc", "voltage0", "input") + + +def test_ignore_channel_with_and_without_direction(): + bl = coverage.IgnoreList( { "channels": [ {"device": "ad9361-phy", "id": "voltage0"}, @@ -73,29 +73,29 @@ def test_blacklist_channel_with_and_without_direction(): } ) # No direction in spec -> matches either direction. - assert bl.channel_blacklisted("ad9361-phy", "voltage0", "input") - assert bl.channel_blacklisted("ad9361-phy", "voltage0", "output") + assert bl.channel_ignored("ad9361-phy", "voltage0", "input") + assert bl.channel_ignored("ad9361-phy", "voltage0", "output") # Direction-qualified glob entry. - assert bl.channel_blacklisted("ad9361-phy", "voltage1", "output") - assert not bl.channel_blacklisted("ad9361-phy", "voltage1", "input") + assert bl.channel_ignored("ad9361-phy", "voltage1", "output") + assert not bl.channel_ignored("ad9361-phy", "voltage1", "input") # Wrong device. - assert not bl.channel_blacklisted("cf-ad9361-lpc", "voltage0", "input") - # A blacklisted channel cascades to its attrs. - assert bl.attr_blacklisted("ad9361-phy", "voltage0", "scale", "input") + assert not bl.channel_ignored("cf-ad9361-lpc", "voltage0", "input") + # An ignored channel cascades to its attrs. + assert bl.attr_ignored("ad9361-phy", "voltage0", "scale", "input") -def test_blacklist_device_level_attribute(): - bl = coverage.Blacklist( +def test_ignore_device_level_attribute(): + bl = coverage.IgnoreList( {"attributes": [{"device": "ad9361-phy", "name": "in_temp0_input"}]} ) - assert bl.attr_blacklisted("ad9361-phy", None, "in_temp0_input", None) - assert not bl.attr_blacklisted("ad9361-phy", None, "frequency", None) + assert bl.attr_ignored("ad9361-phy", None, "in_temp0_input", None) + assert not bl.attr_ignored("ad9361-phy", None, "frequency", None) # A device-level attribute entry (no channel) must not match a channel attr. - assert not bl.attr_blacklisted("ad9361-phy", "voltage0", "in_temp0_input", "input") + assert not bl.attr_ignored("ad9361-phy", "voltage0", "in_temp0_input", "input") -def test_blacklist_channel_attribute_with_direction(): - bl = coverage.Blacklist( +def test_ignore_channel_attribute_with_direction(): + bl = coverage.IgnoreList( { "attributes": [ { @@ -107,23 +107,23 @@ def test_blacklist_channel_attribute_with_direction(): ] } ) - assert bl.attr_blacklisted("ad9361-phy", "voltage0", "hardwaregain", "output") + assert bl.attr_ignored("ad9361-phy", "voltage0", "hardwaregain", "output") # Wrong direction. - assert not bl.attr_blacklisted("ad9361-phy", "voltage0", "hardwaregain", "input") + assert not bl.attr_ignored("ad9361-phy", "voltage0", "hardwaregain", "input") # A channel-attr entry (has channel) must not match a device-level attr. - assert not bl.attr_blacklisted("ad9361-phy", None, "hardwaregain", None) + assert not bl.attr_ignored("ad9361-phy", None, "hardwaregain", None) -def test_blacklist_attribute_globs_everywhere(): - bl = coverage.Blacklist( +def test_ignore_attribute_globs_everywhere(): + bl = coverage.IgnoreList( {"attributes": [{"device": "*", "channel": "*", "name": "raw"}]} ) - assert bl.attr_blacklisted("ad9361-phy", "voltage0", "raw", "input") - assert bl.attr_blacklisted("cf-ad9361-lpc", "voltage7", "raw", "output") - assert not bl.attr_blacklisted("ad9361-phy", "voltage0", "scale", "input") + assert bl.attr_ignored("ad9361-phy", "voltage0", "raw", "input") + assert bl.attr_ignored("cf-ad9361-lpc", "voltage7", "raw", "output") + assert not bl.attr_ignored("ad9361-phy", "voltage0", "scale", "input") -def test_build_context_map_excludes_blacklisted(monkeypatch): +def test_build_context_map_excludes_ignored(monkeypatch): monkeypatch.setattr("pytest_libiio.coverage.iio.Context", lambda uri: FakeContext()) spec = { "attributes": [ @@ -132,7 +132,7 @@ def test_build_context_map_excludes_blacklisted(monkeypatch): ], "channels": [{"device": "dev0", "id": "ch_in"}], } - tracker = coverage.CoverageTracker("dut", "ip:1.2.3.4", blacklist=spec) + tracker = coverage.CoverageTracker("dut", "ip:1.2.3.4", ignore=spec) # Device-level attr dev_a removed, dev_b kept. assert "dev_a" not in tracker.device_attr_reads_writes["dev0"] @@ -151,34 +151,34 @@ def test_build_context_map_excludes_whole_device(monkeypatch): "dut", "ip:1.2.3.4", track_debug_props=True, - blacklist={"devices": ["dev0"]}, + ignore={"devices": ["dev0"]}, ) assert tracker.device_attr_reads_writes == {} assert tracker.channel_attr_reads_writes == {} assert tracker.debug_attr_reads_writes == {} -def test_multi_context_tracker_passes_per_hw_blacklist(monkeypatch): +def test_multi_context_tracker_passes_per_hw_ignore(monkeypatch): monkeypatch.setattr("pytest_libiio.coverage.iio.Context", lambda uri: FakeContext()) mct = coverage.MultiContextTracker() - mct.blacklists = {"dut": {"devices": ["dev0"]}} + mct.ignores = {"dut": {"devices": ["dev0"]}} mct.add_instance("dut", "ip:1.2.3.4") assert mct.trackers["dut"].device_attr_reads_writes == {} - # A hardware name with no blacklist entry is tracked normally. + # A hardware name with no ignore entry is tracked normally. mct.add_instance("other", "ip:5.6.7.8") assert mct.trackers["other"].device_attr_reads_writes != {} -def test_mkpatch_skips_blacklisted_device_attr(monkeypatch): +def test_mkpatch_skips_ignored_device_attr(monkeypatch): from pytest_libiio import mkpatch monkeypatch.setattr("pytest_libiio.coverage.iio.Context", lambda uri: FakeContext()) tracker = coverage.CoverageTracker( "dut", "ip:1.2.3.4", - blacklist={"attributes": [{"device": "dev0", "name": "dev_a"}]}, + ignore={"attributes": [{"device": "dev0", "name": "dev_a"}]}, ) mkpatch.set_coverage_tracker(tracker) try: @@ -193,27 +193,27 @@ def __init__(self, name): self.name = name self._device = object() - # Blacklisted attr: original still runs, but no count is recorded and + # Ignored attr: original still runs, but no count is recorded and # the (absent) key is never indexed -> no KeyError. out = mkpatch._read(Attr("dev_a")) assert out == "val" assert "dev_a" not in tracker.device_attr_reads_writes["dev0"] - # Non-blacklisted attr still increments. + # Non-ignored attr still increments. mkpatch._read(Attr("dev_b")) assert tracker.device_attr_reads_writes["dev0"]["dev_b"] == 1 finally: mkpatch.reset_coverage_tracker() -def test_mkpatch_skips_blacklisted_channel_attr(monkeypatch): +def test_mkpatch_skips_ignored_channel_attr(monkeypatch): from pytest_libiio import mkpatch monkeypatch.setattr("pytest_libiio.coverage.iio.Context", lambda uri: FakeContext()) tracker = coverage.CoverageTracker( "dut", "ip:1.2.3.4", - blacklist={ + ignore={ "attributes": [{"device": "dev0", "channel": "ch_out", "name": "ch_b"}] }, ) @@ -233,14 +233,14 @@ def __init__(self, name): self.name = name self._channel = object() - # Blacklisted channel attr: original still runs, no count, no KeyError. + # Ignored channel attr: original still runs, no count, no KeyError. mkpatch._write(Attr("ch_b"), "5") assert writes == ["5"] assert ( "ch_b" not in tracker.channel_attr_reads_writes["dev0"]["output"]["ch_out"] ) - # Non-blacklisted channel attr still increments. + # Non-ignored channel attr still increments. mkpatch._write(Attr("ch_c"), "6") assert ( tracker.channel_attr_reads_writes["dev0"]["output"]["ch_out"]["ch_c"] == 1 diff --git a/tests/test_mkpatch.py b/tests/test_mkpatch.py index 0f39031..baed795 100644 --- a/tests/test_mkpatch.py +++ b/tests/test_mkpatch.py @@ -114,11 +114,11 @@ def test_sth(iio_uri): assert result.ret == 0 -def test_emulation_coverage_blacklist(testdir): - """Blacklisted devices/channels/attributes are excluded from coverage.""" +def test_emulation_coverage_ignore(testdir): + """Ignored devices/channels/attributes are excluded from coverage.""" time.sleep(sleep) - # Custom hardware map with a per-hardware blacklist section. + # Custom hardware map with a per-hardware ignore section. testdir.makefile( ".yml", custom_map=""" @@ -130,7 +130,7 @@ def test_emulation_coverage_blacklist(testdir): - data_devices: - iio:device2 - iio:device3 - - blacklist: + - ignore: devices: - xadc attributes: @@ -175,12 +175,12 @@ def test_sth(iio_uri): data = json.loads(cov_file.read()) dev = data["device_attr_reads_writes"] - # Whole device blacklisted. + # Whole device ignored. assert "xadc" not in dev - # Device-level attribute blacklisted, siblings retained. + # Device-level attribute ignored, siblings retained. assert "calib_mode_available" not in dev["ad9361-phy"] assert "calib_mode" in dev["ad9361-phy"] - # Channel attribute blacklisted, siblings retained. + # Channel attribute ignored, siblings retained. chan = data["channel_attr_reads_writes"]["ad9361-phy"]["input"]["voltage0"] assert "hardwaregain" not in chan assert "gain_control_mode" in chan diff --git a/tests/test_plugin_unit.py b/tests/test_plugin_unit.py index 31f7102..e33c5c5 100644 --- a/tests/test_plugin_unit.py +++ b/tests/test_plugin_unit.py @@ -126,23 +126,23 @@ def test_gen_markdown_table_and_filename_helpers(tmp_path): assert plugin.get_filename(hw_map, "pluto") == ("pluto.xml", ["d0"]) -def test_extract_blacklists(): +def test_extract_ignores(): hw_map = { "pluto": [ "ad9361-phy", {"emulate": [{"filename": "pluto.xml"}]}, - {"blacklist": {"devices": ["xadc"]}}, + {"ignore": {"devices": ["xadc"]}}, ], "fmcomms2": ["ad9361-phy"], # A malformed entry whose value is not a list is skipped defensively. "weird": None, } - assert plugin.extract_blacklists(hw_map) == {"pluto": {"devices": ["xadc"]}} + assert plugin.extract_ignores(hw_map) == {"pluto": {"devices": ["xadc"]}} -def test_extract_blacklists_handles_empty_map(): - assert plugin.extract_blacklists(None) == {} - assert plugin.extract_blacklists({}) == {} +def test_extract_ignores_handles_empty_map(): + assert plugin.extract_ignores(None) == {} + assert plugin.extract_ignores({}) == {} def test_get_hw_map_variants(monkeypatch, tmp_path):