Skip to content

Commit

Permalink
Add new BoolQueryTab implementation.
Browse files Browse the repository at this point in the history
Signed-off-by: Chris PeBenito <pebenito@ieee.org>
  • Loading branch information
pebenito committed Nov 16, 2023
1 parent 6d0e659 commit b2a77f9
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 5 deletions.
3 changes: 2 additions & 1 deletion setoolsgui/apol.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
# Supported analyses. These are not directly used here, but
# will init the tab registry in widgets.tab for apol's analyses.
# pylint: disable=unused-import
from .widgets import (constraintquery,
from .widgets import (boolquery,
constraintquery,
fsusequery,
genfsconquery,
ibendportconquery,
Expand Down
81 changes: 81 additions & 0 deletions setoolsgui/widgets/boolquery.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# SPDX-License-Identifier: LGPL-2.1-only

from PyQt6 import QtWidgets
import setools

from . import criteria, models, tab

__all__ = ("BoolQueryTab",)


class BoolQueryTab(tab.TableResultTabWidget):

"""A boolean query."""

section = tab.AnalysisSection.Components
tab_title = "Booleans"
mlsonly = False

def __init__(self, policy: setools.SELinuxPolicy, _, /, *,
parent: QtWidgets.QWidget | None = None) -> None:

super().__init__(setools.BoolQuery(policy), None, enable_criteria=True,
enable_browser=True, parent=parent)

self.setWhatsThis("<b>Search Booleans in a SELinux policy.</b>")

#
# Set up criteria widgets
#
name = criteria.BooleanNameCriteriaWidget("Name", self.query, "name",
enable_regex=True,
parent=self.criteria_frame)
name.setToolTip("Search for Booleans by name.")
name.setWhatsThis("<p>Search for Booleans by name.</p>")

state = criteria.BooleanState("Default State", self.query, "default",
enable_any=True,
parent=self.criteria_frame)
state.setToolTip("Search for Booleans by default state.")
state.setWhatsThis("<p>Search for Booleans by default state.</p>")

# Add widgets to layout
self.criteria_frame_layout.addWidget(name, 0, 0, 1, 1)
self.criteria_frame_layout.addWidget(state, 0, 1, 1, 1)
self.criteria_frame_layout.addWidget(self.buttonBox, 1, 0, 1, 2)

# Save widget references
self.criteria = (name, state)

# Set result table's model
self.table_results_model = models.BooleanTable(self.table_results)

#
# Set up browser
#
self.browser.setModel(models.BooleanTable(self.browser,
data=sorted(self.query.policy.bools())))


if __name__ == '__main__':
import sys
import warnings
import pprint
import logging

logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s|%(levelname)s|%(name)s|%(message)s')
warnings.simplefilter("default")

app = QtWidgets.QApplication(sys.argv)
mw = QtWidgets.QMainWindow()
widget = BoolQueryTab(setools.SELinuxPolicy(), mw)
mw.setCentralWidget(widget)
mw.resize(1280, 1024)
whatsthis = QtWidgets.QWhatsThis.createAction(mw)
mw.menuBar().addAction(whatsthis) # type: ignore[union-attr]
mw.setStatusBar(QtWidgets.QStatusBar(mw))
mw.show()
rc = app.exec()
pprint.pprint(widget.save())
sys.exit(rc)
22 changes: 18 additions & 4 deletions setoolsgui/widgets/criteria/boolean.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
# SPDX-License-Identifier: LGPL-2.1-only

from PyQt6 import QtWidgets
import setools

from .. import models
from .combobox import ComboBoxWidget
from .list import ListCriteriaWidget
from .name import NameCriteriaWidget

# Regex for exact matches to types/attrs
VALIDATE_EXACT = r"[A-Za-z0-9._-]*"

__all__ = ("BooleanListCriteriaWidget", "BooleanNameCriteriaWidget",)
__all__ = ("BooleanListCriteriaWidget", "BooleanNameCriteriaWidget", "BooleanState")


class BooleanListCriteriaWidget(ListCriteriaWidget):
Expand Down Expand Up @@ -48,12 +50,24 @@ def __init__(self, title: str, query, attrname: str,
enable_regex=enable_regex, required=required, parent=parent)


class BooleanState(ComboBoxWidget):

"""Criteria selection widget presenting possible Boolean states."""

def __init__(self, title: str, query: setools.PolicyQuery, attrname: str, /, *,
enable_any: bool = True, parent: QtWidgets.QWidget | None = None) -> None:

super().__init__(title, query, attrname, enable_any=enable_any, parent=parent)

self.criteria.addItem("False", False)
self.criteria.addItem("True", True)


if __name__ == '__main__':
import sys
import logging
import warnings
import setools
import pprint

logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s|%(levelname)s|%(name)s|%(message)s')
Expand All @@ -69,8 +83,10 @@ def __init__(self, title: str, query, attrname: str,
layout = QtWidgets.QHBoxLayout(window)
widget1 = BooleanListCriteriaWidget("Test Booleans list", q1, "boolean", parent=window)
widget2 = BooleanNameCriteriaWidget("Test Booleans linedit", q2, "name", parent=window)
widget3 = BooleanState("Test Booleans State", q2, "default", enable_any=True, parent=window)
layout.addWidget(widget1)
layout.addWidget(widget2)
layout.addWidget(widget3)
window.setToolTip("test tooltip")
window.setWhatsThis("test whats this")
mw.setCentralWidget(window)
Expand All @@ -79,6 +95,4 @@ def __init__(self, title: str, query, attrname: str,
mw.menuBar().addAction(whatsthis) # type: ignore[union-attr]
mw.show()
rc = app.exec()
print("Query settings:")
pprint.pprint(q1.boolean)
sys.exit(rc)
58 changes: 58 additions & 0 deletions tests-gui/widgets/test_boolquery.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# SPDX-License-Identifier: GPL-2.0-only
import typing

from PyQt6 import QtWidgets
from pytestqt.qtbot import QtBot

import setools
from setoolsgui.widgets.boolquery import BoolQueryTab

from .criteria.util import build_mock_policy


def test_docs(qtbot: QtBot) -> None:
"""Check that docs are provided for the widget."""
mock_policy = build_mock_policy()
widget = BoolQueryTab(mock_policy, None)
qtbot.addWidget(widget)

assert widget.whatsThis()
assert widget.table_results.whatsThis()
assert widget.raw_results.whatsThis()

for w in widget.criteria:
assert w.toolTip()
assert w.whatsThis()

results = typing.cast(QtWidgets.QTabWidget, widget.results)
for index in range(results.count()):
assert results.tabWhatsThis(index)


def test_layout(qtbot: QtBot) -> None:
"""Test the layout of the criteria frame."""
mock_policy = build_mock_policy()
widget = BoolQueryTab(mock_policy, None)
qtbot.addWidget(widget)

name, state = widget.criteria

assert widget.criteria_frame_layout.columnCount() == 2
assert widget.criteria_frame_layout.rowCount() == 2
assert widget.criteria_frame_layout.itemAtPosition(0, 0).widget() == name
assert widget.criteria_frame_layout.itemAtPosition(0, 1).widget() == state
assert widget.criteria_frame_layout.itemAtPosition(1, 0).widget() == widget.buttonBox
assert widget.criteria_frame_layout.itemAtPosition(1, 1).widget() == widget.buttonBox


def test_criteria_mapping(qtbot: QtBot) -> None:
"""Test that widgets save to the correct query fields."""
mock_policy = build_mock_policy()
widget = BoolQueryTab(mock_policy, None)
qtbot.addWidget(widget)

name, state = widget.criteria

assert isinstance(widget.query, setools.BoolQuery)
assert name.attrname == "name"
assert state.attrname == "default"

0 comments on commit b2a77f9

Please sign in to comment.