mirror of
https://github.com/LorenEteval/Furious.git
synced 2026-09-22 15:04:34 +03:00
Improve logical block spacing
Signed-off-by: Loren Eteval <loren.eteval@proton.me>
This commit is contained in:
@@ -221,6 +221,7 @@ class GuiHy1ItemTLSInsecure(GuiEditorItemTextSwitch):
|
||||
config['insecure'] = False
|
||||
|
||||
return True
|
||||
|
||||
if oldChecked is False:
|
||||
return False
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ def fixLogObjectPath(config, attr: str, value: str, log=True):
|
||||
config['log'][attr] = absolutePath(path)
|
||||
|
||||
result = config['log'][attr]
|
||||
|
||||
if result:
|
||||
try:
|
||||
with open(result, 'x', encoding='utf-8'):
|
||||
|
||||
@@ -133,6 +133,7 @@ def configureXrayStats(
|
||||
config['api'] = currentApi
|
||||
|
||||
configuredServer = currentApi.get('listen')
|
||||
|
||||
if not isinstance(configuredServer, str) or not configuredServer.strip():
|
||||
configuredServer = None
|
||||
|
||||
@@ -143,6 +144,7 @@ def configureXrayStats(
|
||||
currentApi['listen'] = apiServer
|
||||
|
||||
services = currentApi.get('services', [])
|
||||
|
||||
if not isinstance(services, list):
|
||||
services = []
|
||||
|
||||
@@ -159,11 +161,13 @@ def configureXrayStats(
|
||||
config['stats'] = generated['stats']
|
||||
|
||||
policy = config.get('policy')
|
||||
|
||||
if not isinstance(policy, dict):
|
||||
policy = {}
|
||||
config['policy'] = policy
|
||||
|
||||
systemPolicy = policy.get('system')
|
||||
|
||||
if not isinstance(systemPolicy, dict):
|
||||
systemPolicy = {}
|
||||
policy['system'] = systemPolicy
|
||||
|
||||
@@ -420,6 +420,7 @@ class PluginRegistry:
|
||||
|
||||
for configType in configurationTypes:
|
||||
self._configurationFactories[configType] = entry
|
||||
|
||||
for runtimeType in runtimeTypes:
|
||||
self._runtimeFactories[runtimeType] = entry
|
||||
elif isinstance(capability, TrafficStatsProvider):
|
||||
|
||||
+43
@@ -272,6 +272,7 @@ class _RequestPayload:
|
||||
def runNetworkProbe(iterations=100):
|
||||
"""Verify native teardown releases both reply registries under compilation."""
|
||||
application()
|
||||
|
||||
result = {}
|
||||
|
||||
for managerType, contextAttribute in (
|
||||
@@ -286,8 +287,10 @@ def runNetworkProbe(iterations=100):
|
||||
manager = managerType()
|
||||
payload = _RequestPayload()
|
||||
reply = _PendingReply(manager)
|
||||
|
||||
references.extend((weakref.ref(payload), weakref.ref(reply)))
|
||||
reply.destroyed.connect(lambda *_args: destroyed.append(True))
|
||||
|
||||
manager.get = lambda _request: reply
|
||||
|
||||
if isinstance(manager, HttpGetManager):
|
||||
@@ -306,6 +309,7 @@ def runNetworkProbe(iterations=100):
|
||||
manager.deleteLater()
|
||||
|
||||
processQtEvents()
|
||||
|
||||
assert not isValid(reply)
|
||||
assert not getattr(manager, contextAttribute)
|
||||
|
||||
@@ -317,6 +321,7 @@ def runNetworkProbe(iterations=100):
|
||||
|
||||
assert len(destroyed) == iterations
|
||||
assert all(reference() is None for reference in references)
|
||||
|
||||
result[managerType.__name__ + ':' + terminal] = iterations
|
||||
|
||||
return result
|
||||
@@ -325,18 +330,22 @@ def runNetworkProbe(iterations=100):
|
||||
def runInfrastructureProbe(iterations=100):
|
||||
"""Check signal, mask, and animation ownership under real Qt destruction."""
|
||||
application()
|
||||
|
||||
result = {}
|
||||
|
||||
for closeMethod in CLOSE_METHODS:
|
||||
destroyed = []
|
||||
|
||||
for _ in range(iterations):
|
||||
dialog = AppQDialog()
|
||||
dialog.destroyed.connect(lambda *_args: destroyed.append(True))
|
||||
reference = weakref.ref(dialog)
|
||||
key = dialog._lifetimeKey
|
||||
|
||||
dialog.open()
|
||||
getattr(dialog, closeMethod)()
|
||||
dialog.open()
|
||||
|
||||
del dialog
|
||||
processQtEvents()
|
||||
|
||||
@@ -346,37 +355,49 @@ def runInfrastructureProbe(iterations=100):
|
||||
|
||||
getattr(reference(), closeMethod)()
|
||||
processQtEvents()
|
||||
|
||||
assert reference() is None
|
||||
assert key not in AppQDialog._openDialogs
|
||||
|
||||
assert len(destroyed) == iterations
|
||||
|
||||
result['reopenAfter' + closeMethod.title()] = iterations
|
||||
|
||||
routingReferences = []
|
||||
routingDestroyed = []
|
||||
|
||||
for _ in range(iterations):
|
||||
dialog = RoutingRulesDialog({'rules': [{'ruleTag': 'keep'}]})
|
||||
dialog.open()
|
||||
dialog.listView.setCurrentIndex(dialog.listView.rulesModel.index(0, 0))
|
||||
|
||||
dialog.deleteRule()
|
||||
|
||||
confirmation = next(
|
||||
item
|
||||
for item in AppQDialog._openDialogs.values()
|
||||
if isinstance(item, AppQMessageBox)
|
||||
)
|
||||
|
||||
for item in (dialog, confirmation):
|
||||
routingReferences.append(weakref.ref(item))
|
||||
item.destroyed.connect(lambda *_args: routingDestroyed.append(True))
|
||||
|
||||
del item
|
||||
|
||||
dialog.deleteLater()
|
||||
processQtEvents()
|
||||
|
||||
assert not isValid(dialog) and not isValid(confirmation)
|
||||
|
||||
del dialog, confirmation
|
||||
|
||||
collectAtBoundary()
|
||||
|
||||
assert len(routingDestroyed) == iterations * 2
|
||||
assert all(reference() is None for reference in routingReferences)
|
||||
assert not AppQDialog._openDialogs
|
||||
|
||||
result['routingOwnerFirst'] = iterations
|
||||
|
||||
for senderFirst in (True, False):
|
||||
@@ -403,6 +424,7 @@ def runInfrastructureProbe(iterations=100):
|
||||
counts.append(survivor.receivers(QtCore.SIGNAL('destroyed(QObject*)')))
|
||||
|
||||
assert counts == [counts[0]] * iterations, counts
|
||||
|
||||
result['senderFirst' if senderFirst else 'receiverFirst'] = iterations
|
||||
|
||||
survivor.deleteLater()
|
||||
@@ -421,6 +443,7 @@ def runInfrastructureProbe(iterations=100):
|
||||
)
|
||||
|
||||
transition.apply(lambda: None)
|
||||
|
||||
animation = next(iter(transition._animations))
|
||||
overlay = window.findChild(QWidget, transition.OverlayObjectName)
|
||||
|
||||
@@ -435,6 +458,7 @@ def runInfrastructureProbe(iterations=100):
|
||||
else:
|
||||
transition.deleteLater()
|
||||
processQtEvents()
|
||||
|
||||
window.deleteLater()
|
||||
|
||||
processQtEvents()
|
||||
@@ -463,6 +487,7 @@ def runInfrastructureProbe(iterations=100):
|
||||
assert not isValid(mask)
|
||||
|
||||
assert not AppQDialog._openDialogs
|
||||
|
||||
result['messageBoxDeleted'] = iterations
|
||||
finally:
|
||||
owner.deleteLater()
|
||||
@@ -474,63 +499,81 @@ def runInfrastructureProbe(iterations=100):
|
||||
def runConfirmationProbe(iterations=100):
|
||||
"""Check native menu ownership and representative view-owned prompts."""
|
||||
application()
|
||||
|
||||
result = {}
|
||||
|
||||
for explicitOwner in (False, True):
|
||||
references = []
|
||||
destroyed = []
|
||||
|
||||
for _ in range(iterations):
|
||||
owner = QWidget()
|
||||
menu = AppQMenu(parent=owner if explicitOwner else None)
|
||||
action = AppQAction('Menu fixture', menu=menu, parent=owner)
|
||||
|
||||
references.append(weakref.ref(menu))
|
||||
menu.destroyed.connect(lambda *_args: destroyed.append(True))
|
||||
|
||||
action.deleteLater()
|
||||
processQtEvents()
|
||||
|
||||
assert not isValid(action)
|
||||
assert isValid(menu) == explicitOwner
|
||||
|
||||
owner.deleteLater()
|
||||
processQtEvents()
|
||||
|
||||
del action, menu, owner
|
||||
|
||||
assert len(destroyed) == iterations
|
||||
assert all(reference() is None for reference in references)
|
||||
|
||||
result['widgetOwnedMenu' if explicitOwner else 'actionOwnedMenu'] = iterations
|
||||
|
||||
originalAssetDirectory = assetModule.XRAY_ASSET_DIR
|
||||
|
||||
try:
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
assetModule.XRAY_ASSET_DIR = Path(directory)
|
||||
asset = Path(directory) / 'fixture.dat'
|
||||
asset.write_bytes(b'keep')
|
||||
|
||||
for overwrite in (False, True):
|
||||
references = []
|
||||
destroyed = []
|
||||
|
||||
for _ in range(iterations):
|
||||
owner = QWidget()
|
||||
view = XrayAssetListView(parent=owner)
|
||||
view.setCurrentIndex(view.model().index(0, 0))
|
||||
|
||||
if overwrite:
|
||||
view.appendNewItem(str(asset))
|
||||
else:
|
||||
view.deleteSelectedItem()
|
||||
|
||||
confirmation = next(iter(AppQDialog._openDialogs.values()))
|
||||
references.append(weakref.ref(confirmation))
|
||||
confirmation.destroyed.connect(
|
||||
lambda *_args: destroyed.append(True)
|
||||
)
|
||||
|
||||
view.deleteLater()
|
||||
processQtEvents()
|
||||
|
||||
assert not isValid(view) and not isValid(confirmation)
|
||||
assert isValid(owner)
|
||||
assert asset.read_bytes() == b'keep'
|
||||
|
||||
owner.deleteLater()
|
||||
processQtEvents()
|
||||
|
||||
del confirmation, view, owner
|
||||
|
||||
assert len(destroyed) == iterations
|
||||
assert all(reference() is None for reference in references)
|
||||
assert not AppQDialog._openDialogs
|
||||
|
||||
result[
|
||||
'assetOverwriteOwnerFirst' if overwrite else 'assetDeleteOwnerFirst'
|
||||
] = iterations
|
||||
|
||||
@@ -1528,6 +1528,7 @@ class VeryHeavyGenerationLogManagerTest(unittest.TestCase):
|
||||
return time.perf_counter_ns() - started
|
||||
|
||||
matrix = []
|
||||
|
||||
for size in (100, 1_000, 10_000):
|
||||
samples = {
|
||||
name: []
|
||||
@@ -1544,13 +1545,16 @@ class VeryHeavyGenerationLogManagerTest(unittest.TestCase):
|
||||
'oldest_eviction',
|
||||
)
|
||||
}
|
||||
|
||||
for _repetition in range(5):
|
||||
manager = LogManager(
|
||||
maximumEntries=size * 2 + 10,
|
||||
autoClearMaximumEntries=size,
|
||||
)
|
||||
|
||||
for index in range(size):
|
||||
manager.append(str(index), CORE_LOG_CATEGORY)
|
||||
|
||||
samples['normal_append'].append(
|
||||
elapsed(lambda: manager.append('ordinary'))
|
||||
)
|
||||
@@ -1559,22 +1563,27 @@ class VeryHeavyGenerationLogManagerTest(unittest.TestCase):
|
||||
)
|
||||
|
||||
manager = LogManager(maximumEntries=size + 10, autoClearEnabled=False)
|
||||
|
||||
for index in range(size):
|
||||
manager.append(str(index), CORE_LOG_CATEGORY)
|
||||
|
||||
samples['category_snapshot'].append(
|
||||
elapsed(lambda: manager.snapshot(CORE_LOG_CATEGORY))
|
||||
)
|
||||
samples['runtime_clear'].append(
|
||||
elapsed(lambda: manager.clear(runtimeOnly=True))
|
||||
)
|
||||
|
||||
with manager._lock:
|
||||
samples['cleanup_64'].append(
|
||||
elapsed(lambda: manager._cleanupRetiredLocked())
|
||||
)
|
||||
|
||||
manager = LogManager(maximumEntries=size + 10, autoClearEnabled=False)
|
||||
|
||||
for index in range(size):
|
||||
manager.append(str(index), APPLICATION_LOG_CATEGORY)
|
||||
|
||||
samples['sole_category_clear'].append(
|
||||
elapsed(lambda: manager.clear(APPLICATION_LOG_CATEGORY))
|
||||
)
|
||||
@@ -1583,14 +1592,17 @@ class VeryHeavyGenerationLogManagerTest(unittest.TestCase):
|
||||
maximumEntries=size * 2 + 10,
|
||||
autoClearEnabled=False,
|
||||
)
|
||||
|
||||
for index in range(size):
|
||||
manager.append(str(index), CORE_LOG_CATEGORY)
|
||||
manager.append('shared', TUN2SOCKS_LOG_CATEGORY)
|
||||
|
||||
samples['shared_category_clear'].append(
|
||||
elapsed(lambda: manager.clear(CORE_LOG_CATEGORY))
|
||||
)
|
||||
|
||||
manager = LogManager(maximumEntries=size + 10, autoClearEnabled=False)
|
||||
|
||||
for index in range(size):
|
||||
manager.append(
|
||||
str(index),
|
||||
@@ -1600,10 +1612,12 @@ class VeryHeavyGenerationLogManagerTest(unittest.TestCase):
|
||||
TUN2SOCKS_LOG_CATEGORY,
|
||||
)[index % 3],
|
||||
)
|
||||
|
||||
samples['global_snapshot'].append(elapsed(lambda: manager.snapshot()))
|
||||
samples['clear_all'].append(elapsed(lambda: manager.clear()))
|
||||
|
||||
manager = LogManager(maximumEntries=size, autoClearEnabled=False)
|
||||
|
||||
for index in range(size):
|
||||
manager.append(
|
||||
str(index),
|
||||
@@ -1613,6 +1627,7 @@ class VeryHeavyGenerationLogManagerTest(unittest.TestCase):
|
||||
TUN2SOCKS_LOG_CATEGORY,
|
||||
)[index % 3],
|
||||
)
|
||||
|
||||
samples['oldest_eviction'].append(
|
||||
elapsed(lambda: manager.append('evict'))
|
||||
)
|
||||
@@ -1632,6 +1647,7 @@ class VeryHeavyGenerationLogManagerTest(unittest.TestCase):
|
||||
for name in matrix[0]
|
||||
if name != 'n'
|
||||
}
|
||||
|
||||
for name in (
|
||||
'normal_append_us',
|
||||
'core_rollover_us',
|
||||
@@ -1642,6 +1658,7 @@ class VeryHeavyGenerationLogManagerTest(unittest.TestCase):
|
||||
'oldest_eviction_us',
|
||||
):
|
||||
self.assertLess(ratios[name], 50)
|
||||
|
||||
self.report('operation-scaling-matrix', samples=matrix, ratios=ratios)
|
||||
|
||||
def testAppendLatencyWithRolloverRetentionAndBacklog(self):
|
||||
@@ -1715,8 +1732,10 @@ class VeryHeavyGenerationLogManagerTest(unittest.TestCase):
|
||||
def testCleanupLatencyDoesNotScaleWithBacklog(self):
|
||||
"""Keep append cleanup capped at one for geometrically larger queues."""
|
||||
results = []
|
||||
|
||||
for backlog in (64, 1_000, 10_000):
|
||||
samples = []
|
||||
|
||||
for _repetition in range(9):
|
||||
manager = LogManager(
|
||||
maximumEntries=backlog + 10,
|
||||
@@ -1726,17 +1745,25 @@ class VeryHeavyGenerationLogManagerTest(unittest.TestCase):
|
||||
)
|
||||
manager.RetiredCleanupBudget = 64
|
||||
manager.AppendRetiredCleanupBudget = 1
|
||||
|
||||
for index in range(backlog):
|
||||
manager.append(str(index), CORE_LOG_CATEGORY)
|
||||
|
||||
manager.clear(runtimeOnly=True)
|
||||
before = manager.retiredEntryCount
|
||||
|
||||
started = time.perf_counter_ns()
|
||||
manager.append('new')
|
||||
samples.append(time.perf_counter_ns() - started)
|
||||
|
||||
self.assertEqual(manager.retiredEntryCount, max(0, before - 1))
|
||||
|
||||
results.append({'backlog': backlog, 'median_us': median(samples) / 1_000})
|
||||
|
||||
ratio = results[-1]['median_us'] / max(results[0]['median_us'], 0.001)
|
||||
|
||||
self.assertLess(ratio, 20)
|
||||
|
||||
self.report('cleanup-backlog-latency', samples=results, endpoint_ratio=ratio)
|
||||
|
||||
def testAdversarialClearRateCannotGrowPhysicalBacklog(self):
|
||||
@@ -1942,6 +1969,7 @@ class VeryHeavyGenerationLogManagerTest(unittest.TestCase):
|
||||
capture_output=True,
|
||||
text=True,
|
||||
).stdout
|
||||
|
||||
baselineModule = types.ModuleType('tests._baseline_log_manager')
|
||||
previousModule = sys.modules.get(baselineModule.__name__)
|
||||
sys.modules[baselineModule.__name__] = baselineModule
|
||||
@@ -1959,47 +1987,60 @@ class VeryHeavyGenerationLogManagerTest(unittest.TestCase):
|
||||
|
||||
def benchmark(managerClass):
|
||||
results = {}
|
||||
|
||||
manager = managerClass(maximumEntries=50_000, autoClearEnabled=False)
|
||||
|
||||
started = time.perf_counter_ns()
|
||||
for index in range(50_000):
|
||||
manager.append(str(index), APPLICATION_LOG_CATEGORY)
|
||||
|
||||
results['steady_append_ms'] = (time.perf_counter_ns() - started) / 1e6
|
||||
|
||||
manager = managerClass(
|
||||
maximumEntries=50_000,
|
||||
autoClearMaximumEntries=20_000,
|
||||
)
|
||||
|
||||
for index in range(20_000):
|
||||
manager.append(str(index), CORE_LOG_CATEGORY)
|
||||
for index in range(20_000):
|
||||
manager.append(str(index), TUN2SOCKS_LOG_CATEGORY)
|
||||
|
||||
started = time.perf_counter_ns()
|
||||
manager.append('trigger', CORE_LOG_CATEGORY)
|
||||
results['core_rollover_us'] = (time.perf_counter_ns() - started) / 1e3
|
||||
|
||||
manager = managerClass(maximumEntries=50_000, autoClearEnabled=False)
|
||||
|
||||
for index in range(30_000):
|
||||
manager.append(
|
||||
str(index),
|
||||
CORE_LOG_CATEGORY if index % 5 == 0 else APPLICATION_LOG_CATEGORY,
|
||||
)
|
||||
|
||||
started = time.perf_counter_ns()
|
||||
manager.snapshot(CORE_LOG_CATEGORY)
|
||||
results['category_snapshot_us'] = (time.perf_counter_ns() - started) / 1e3
|
||||
|
||||
started = time.perf_counter_ns()
|
||||
manager.snapshot()
|
||||
results['global_snapshot_us'] = (time.perf_counter_ns() - started) / 1e3
|
||||
|
||||
manager = managerClass(maximumEntries=1_000, autoClearEnabled=False)
|
||||
|
||||
started = time.perf_counter_ns()
|
||||
for index in range(50_000):
|
||||
manager.append(str(index), APPLICATION_LOG_CATEGORY)
|
||||
|
||||
results['retention_heavy_ms'] = (time.perf_counter_ns() - started) / 1e6
|
||||
|
||||
return results
|
||||
|
||||
current = benchmark(LogManager)
|
||||
baseline = benchmark(baselineModule.LogManager)
|
||||
|
||||
self.assertEqual(LogManager(maximumEntries=1).entries(), tuple())
|
||||
|
||||
self.report(
|
||||
'baseline-comparison',
|
||||
baseline_revision=revision,
|
||||
|
||||
@@ -238,6 +238,7 @@ class QtLifetimeTest(unittest.TestCase):
|
||||
owner = QWidget()
|
||||
menu = AppQMenu(parent=owner if explicitOwner else None)
|
||||
action = AppQAction('Menu fixture', menu=menu, parent=owner)
|
||||
|
||||
references.append(weakref.ref(menu))
|
||||
menu.destroyed.connect(lambda *_args: destroyed.append(True))
|
||||
|
||||
@@ -245,11 +246,13 @@ class QtLifetimeTest(unittest.TestCase):
|
||||
processQtEvents()
|
||||
|
||||
self.assertFalse(isValid(action))
|
||||
|
||||
try:
|
||||
self.assertEqual(isValid(menu), explicitOwner)
|
||||
finally:
|
||||
if isValid(menu):
|
||||
menu.deleteLater()
|
||||
|
||||
owner.deleteLater()
|
||||
processQtEvents()
|
||||
|
||||
@@ -290,8 +293,10 @@ class QtLifetimeTest(unittest.TestCase):
|
||||
with self.subTest(platform=platform, family=family):
|
||||
references = []
|
||||
destroyed = []
|
||||
|
||||
for _ in range(20):
|
||||
parent = QWidget()
|
||||
|
||||
if family == 'servers':
|
||||
view = ServerTableView(
|
||||
parent=parent,
|
||||
@@ -308,6 +313,7 @@ class QtLifetimeTest(unittest.TestCase):
|
||||
|
||||
view.setCurrentIndex(view.model().index(0, 0))
|
||||
module = type(view).__module__
|
||||
|
||||
with mock.patch(module + '.PLATFORM', platform):
|
||||
if family == 'assetOverwrite':
|
||||
view.appendNewItem(str(asset))
|
||||
@@ -327,9 +333,11 @@ class QtLifetimeTest(unittest.TestCase):
|
||||
try:
|
||||
view.deleteLater()
|
||||
processQtEvents()
|
||||
|
||||
self.assertFalse(isValid(view))
|
||||
self.assertFalse(isValid(confirmation))
|
||||
self.assertTrue(isValid(parent))
|
||||
|
||||
self.assertEqual(profiles, [profile])
|
||||
self.assertIn('fixture', subscriptions)
|
||||
self.assertIn('fixture', routings)
|
||||
@@ -337,6 +345,7 @@ class QtLifetimeTest(unittest.TestCase):
|
||||
finally:
|
||||
if isValid(confirmation):
|
||||
confirmation.reject()
|
||||
|
||||
parent.deleteLater()
|
||||
processQtEvents()
|
||||
|
||||
|
||||
@@ -186,6 +186,7 @@ class HttpGetManagerLifetimeTest(unittest.TestCase):
|
||||
for _ in range(30):
|
||||
payload = _ResponseBody(b'fixture')
|
||||
references.append(weakref.ref(payload))
|
||||
|
||||
reply = _ManagedReply(manager)
|
||||
references.append(weakref.ref(reply))
|
||||
reply.destroyed.connect(lambda *_args: destroyed.append(True))
|
||||
@@ -202,6 +203,7 @@ class HttpGetManagerLifetimeTest(unittest.TestCase):
|
||||
|
||||
self.assertFalse(isValid(reply))
|
||||
self.assertFalse(getattr(manager, contextAttribute))
|
||||
|
||||
del reply
|
||||
|
||||
self.assertEqual(len(destroyed), 30)
|
||||
@@ -238,6 +240,7 @@ class HttpGetManagerLifetimeTest(unittest.TestCase):
|
||||
"""A completed reply cannot invoke hooks again before deferred deletion."""
|
||||
manager = _CapturingHttpGetManager()
|
||||
self.addCleanup(manager.deleteLater)
|
||||
|
||||
reply = manager.webGET('https://invalid.test', marker='fixture')
|
||||
|
||||
with patch.object(manager, 'successCallback') as completed:
|
||||
@@ -245,7 +248,9 @@ class HttpGetManagerLifetimeTest(unittest.TestCase):
|
||||
reply.finished.emit()
|
||||
|
||||
completed.assert_called_once_with(reply, marker='fixture')
|
||||
|
||||
processQtEvents()
|
||||
|
||||
self.assertFalse(isValid(reply))
|
||||
|
||||
capabilityId = 'fixture.navigation'
|
||||
|
||||
@@ -1655,20 +1655,26 @@ class UnifiedLogPageTest(unittest.TestCase):
|
||||
with isolatedSettings():
|
||||
stack = QStackedWidget()
|
||||
pages = [LogPage(manager=LogManager(maximumEntries=3)) for _ in range(2)]
|
||||
|
||||
for page in pages:
|
||||
stack.addWidget(page)
|
||||
|
||||
self.addCleanup(stack.deleteLater)
|
||||
self.addCleanup(stack.close)
|
||||
self.addCleanup(QTest.keyRelease, stack, QtCore.Qt.Key_Control)
|
||||
|
||||
stack.show()
|
||||
stack.activateWindow()
|
||||
|
||||
for page in (pages[0], pages[1], pages[0]):
|
||||
stack.setCurrentWidget(page)
|
||||
page.textBrowser.setFocus()
|
||||
processQtEvents()
|
||||
|
||||
QTest.keyClick(
|
||||
page.textBrowser, QtCore.Qt.Key_F, QtCore.Qt.ControlModifier
|
||||
)
|
||||
|
||||
self.assertTrue(waitFor(page.searchLineEdit.hasFocus))
|
||||
|
||||
def testLabelsOwnTheirDynamicTranslation(self):
|
||||
|
||||
Reference in New Issue
Block a user