@@ -321,16 +321,16 @@ class TestMIACase(unittest.TestCase):
321
321
- tearDownClass: called after tests in the individual class
322
322
"""
323
323
324
- def add_visualized_tag (self , input_filter , tag , timeout = 5000 ):
324
+ def add_visualized_tag (self , widget , tag , timeout = 5000 ):
325
325
"""
326
326
Selects a tag to display from the "Visualized tags" pop-up.
327
327
328
328
This method waits for the tag selection dialog to become available
329
329
within the given timeout period, locates the specified tag in the
330
330
tag list, selects it, and confirms the dialog.
331
331
332
- :param input_filter : The input filter containing the dialog
333
- with visualized tags.
332
+ :param widget : The input filter containing the dialog
333
+ with visualized tags.
334
334
:param tag (str): The tag name to select and visualize.
335
335
:param timeout (int): Maximum time to wait for the dialog to appear,
336
336
in milliseconds. Defaults to 5000 ms.
@@ -344,7 +344,7 @@ def add_visualized_tag(self, input_filter, tag, timeout=5000):
344
344
345
345
while time .time () - start_time < timeout_secs :
346
346
347
- if getattr (input_filter , "dialog" , None ):
347
+ if getattr (widget , "dialog" , None ):
348
348
break
349
349
350
350
self ._app .processEvents ()
@@ -353,7 +353,7 @@ def add_visualized_tag(self, input_filter, tag, timeout=5000):
353
353
else :
354
354
raise RuntimeError ("Dialog not available" )
355
355
356
- dialog = input_filter .dialog
356
+ dialog = widget .dialog
357
357
visualized_tags = dialog .layout ().itemAt (0 ).widget ()
358
358
359
359
if not visualized_tags :
@@ -7443,146 +7443,126 @@ def test_display_filter(self):
7443
7443
# system in order to make the necessary corrections.
7444
7444
# @unittest.skip("skip this test until it has been repaired.")
7445
7445
def test_filter_widget (self ):
7446
- """Places a node of the "Input_Filter" process, feeds in documents
7447
- and opens up the "FilterWidget()" to modify its parameters.
7446
+ """
7447
+ Tests the `FilterWidget` class used for filtering input data within a
7448
+ Capsul pipeline node.
7449
+
7450
+ This test:
7451
+ - Switches to the V1 node controller (if not already active)
7452
+ - Adds an `Input_Filter` process to the pipeline
7453
+ - Feeds in documents from a test project
7454
+ - Opens the filter widget for the added node
7455
+ - Performs various filtering actions:
7456
+ * Searching for documents by name
7457
+ * Toggling tag visibility
7458
+ * Filtering by a specific tag (mocking user interaction)
7459
+
7460
+ The `FilterWidget` is GUI-independent and works in both V1 and V2 node
7461
+ controller UIs. Only the V1 GUI is exercised here.
7448
7462
7449
- Tests the class FilterWidget() within the Node Controller V1
7450
- (class NodeController()). The class FilterWidget() is
7451
- independent on the Node
7452
- Controller version (V1 or V2) and can be used in both of them.
7463
+ Mocks:
7464
+ - `PopUpSelectTagCountTable.exec_()`
7453
7465
"""
7454
7466
config = Config (properties_path = self .properties_path )
7455
- controlV1_ver = config .isControlV1 ()
7467
+ controlV1 = config .isControlV1 ()
7456
7468
7457
7469
# Switch to V1 node controller GUI, if necessary
7458
- if not controlV1_ver :
7470
+ if not controlV1 :
7459
7471
config .setControlV1 (True )
7460
7472
self .restart_MIA ()
7461
7473
7462
7474
# Opens project 8 and switches to it
7463
7475
project_8_path = self .get_new_test_project ()
7464
7476
self .main_window .switch_project (project_8_path , "project_8" )
7465
7477
7466
- with self .main_window .project .database .data () as database_data :
7467
- DOCUMENT_1 = database_data .get_document_names (COLLECTION_CURRENT )[
7468
- 0
7469
- ]
7470
- DOCUMENT_2 = database_data .get_document_names (COLLECTION_CURRENT )[
7471
- 1
7472
- ]
7478
+ with self .main_window .project .database .data () as db :
7479
+ doc1 , doc2 = db .get_document_names (COLLECTION_CURRENT )[:2 ]
7473
7480
7474
7481
ppl_edt_tabs = self .main_window .pipeline_manager .pipelineEditorTabs
7475
7482
node_ctrler = self .main_window .pipeline_manager .nodeController
7476
7483
self .main_window .tabs .setCurrentIndex (2 )
7477
7484
7478
- # Adds the process "input_filter_1"
7479
- process_class = Input_Filter
7480
- ppl_edt_tabs . get_current_editor () .click_pos = QPoint (450 , 500 )
7481
- ppl_edt_tabs . get_current_editor (). add_named_process (process_class )
7485
+ # Add Input_Filter node
7486
+ editor = ppl_edt_tabs . get_current_editor ()
7487
+ editor .click_pos = QPoint (450 , 500 )
7488
+ editor . add_named_process (Input_Filter )
7482
7489
pipeline = ppl_edt_tabs .get_current_pipeline ()
7483
7490
7484
- # Exports the input plugs for "input_filter_1"
7485
- ppl_edt_tabs .get_current_editor ().current_node_name = "input_filter_1"
7486
- (
7487
- ppl_edt_tabs .get_current_editor
7488
- )().export_node_unconnected_mandatory_plugs ()
7489
-
7490
- # Displays parameters of the "inputs" node
7491
+ # Export mandatory plugs and display parameters
7492
+ editor .current_node_name = "input_filter_1"
7493
+ editor .export_node_unconnected_mandatory_plugs ()
7491
7494
input_process = pipeline .nodes ["" ].process
7492
7495
node_ctrler .display_parameters (
7493
7496
"inputs" , get_process_instance (input_process ), pipeline
7494
7497
)
7495
7498
7496
- # Opens a filter for the plug "input" of the "inputs" node
7497
- parameters = (0 , pipeline , type (Undefined ))
7499
+ # Show filter for input plug of "inputs" node
7498
7500
node_ctrler .display_filter (
7499
- "inputs" , "input" , parameters , input_process
7501
+ "inputs" , "input" , ( 0 , pipeline , type ( Undefined )) , input_process
7500
7502
)
7503
+ node_ctrler .pop_up .ok_clicked () # Select all records
7501
7504
7502
- # Selects all records in the "input" node
7503
- plug_filter = node_ctrler .pop_up
7504
-
7505
- plug_filter .ok_clicked ()
7506
-
7507
- # Opens the filter widget for the node "input_filter_1"
7505
+ # Open FilterWidget
7508
7506
ppl_edt_tabs .open_filter ("input_filter_1" )
7509
7507
input_filter = ppl_edt_tabs .filter_widget
7510
7508
7511
- index_DOCUMENT_1 = input_filter .table_data .get_scan_row (DOCUMENT_1 )
7512
- index_DOCUMENT_2 = input_filter .table_data .get_scan_row (DOCUMENT_2 )
7509
+ idx_doc1 = input_filter .table_data .get_scan_row (doc1 )
7510
+ idx_doc2 = input_filter .table_data .get_scan_row (doc2 )
7513
7511
7514
- # Tries to search for an empty string and asserts that none of the
7515
- # documents are hidden
7512
+ # Filter with empty string, all rows should be visible
7516
7513
input_filter .search_str ("" )
7517
7514
7518
- # Test "DOCUMENT_1" is not hidden
7515
+ # Test doc1 and doc2 are not hidden
7519
7516
if platform .system () == "Windows" :
7520
7517
print (
7521
- "L7522input_filter .table_data.isRowHidden(index_DOCUMENT_1 ): " ,
7522
- input_filter .table_data .isRowHidden (index_DOCUMENT_1 ),
7518
+ "L7517 input_filter .table_data.isRowHidden(idx_doc1 ): " ,
7519
+ input_filter .table_data .isRowHidden (idx_doc1 ),
7523
7520
)
7524
-
7525
- else :
7526
- self .assertFalse (
7527
- input_filter .table_data .isRowHidden (index_DOCUMENT_1 )
7528
- )
7529
-
7530
- # Test "DOCUMENT_2" is not hidden
7531
- if platform .system () == "Windows" :
7532
7521
print (
7533
- "L7534input_filter .table_data.isRowHidden(index_DOCUMENT_2 ): " ,
7534
- input_filter .table_data .isRowHidden (index_DOCUMENT_2 ),
7522
+ "L7521 input_filter .table_data.isRowHidden(idx_doc2 ): " ,
7523
+ input_filter .table_data .isRowHidden (idx_doc2 ),
7535
7524
)
7536
7525
7537
7526
else :
7538
- self .assertFalse (
7539
- input_filter .table_data .isRowHidden (index_DOCUMENT_2 )
7540
- )
7527
+ self .assertFalse (input_filter .table_data .isRowHidden (idx_doc1 ))
7528
+ self .assertFalse (input_filter .table_data .isRowHidden (idx_doc2 ))
7541
7529
7542
- # Searches for "DOCUMENT_2" and verifies that "DOCUMENT_1" is hidden
7543
- input_filter .search_str (DOCUMENT_2 )
7544
- self .assertTrue (input_filter .table_data .isRowHidden (index_DOCUMENT_1 ))
7530
+ # Search for doc2: doc1 hidden, doc2 visible
7531
+ input_filter .search_str (doc2 )
7532
+ self .assertTrue (input_filter .table_data .isRowHidden (idx_doc1 ))
7545
7533
7546
7534
if platform .system () == "Windows" :
7547
7535
print (
7548
- "L7547input_filter .table_data.isRowHidden(index_DOCUMENT_2 ): " ,
7549
- input_filter .table_data .isRowHidden (index_DOCUMENT_2 ),
7536
+ "L7535 input_filter .table_data.isRowHidden(idx_doc2 ): " ,
7537
+ input_filter .table_data .isRowHidden (idx_doc2 ),
7550
7538
)
7551
7539
7552
7540
else :
7553
- self .assertFalse (
7554
- input_filter .table_data .isRowHidden (index_DOCUMENT_2 )
7555
- )
7541
+ self .assertFalse (input_filter .table_data .isRowHidden (idx_doc2 ))
7556
7542
7557
- # Resets the search bar and assert that none of the documents
7558
- # are hidden
7543
+ # Reset search, both documents visible again
7559
7544
input_filter .reset_search_bar ()
7560
7545
7561
- # Test "DOCUMENT_1" is not hidden
7562
7546
if platform .system () == "Windows" :
7563
7547
print (
7564
- "L7563input_filter .table_data.isRowHidden(index_DOCUMENT_1 ): " ,
7565
- input_filter .table_data .isRowHidden (index_DOCUMENT_1 ),
7548
+ "L7547 input_filter .table_data.isRowHidden(idx_doc1 ): " ,
7549
+ input_filter .table_data .isRowHidden (idx_doc1 ),
7566
7550
)
7567
-
7568
- else :
7569
- self .assertFalse (
7570
- input_filter .table_data .isRowHidden (index_DOCUMENT_1 )
7571
- )
7572
-
7573
- # Test "DOCUMENT_2" is not hidden
7574
- if platform .system () == "Windows" :
7575
7551
print (
7576
- "L7575input_filter .table_data.isRowHidden(index_DOCUMENT_2 ): " ,
7577
- input_filter .table_data .isRowHidden (index_DOCUMENT_2 ),
7552
+ "L7551 input_filter .table_data.isRowHiddenidx_doc2 ): " ,
7553
+ input_filter .table_data .isRowHidden (idx_doc2 ),
7578
7554
)
7579
7555
7580
7556
else :
7581
- self .assertFalse (
7582
- input_filter .table_data .isRowHidden (index_DOCUMENT_2 )
7583
- )
7557
+ self .assertFalse (input_filter .table_data .isRowHidden (idx_doc1 ))
7558
+ self .assertFalse (input_filter .table_data .isRowHidden (idx_doc2 ))
7559
+
7560
+ tag_col_idx = input_filter .table_data .get_tag_column ("AcquisitionDate" )
7561
+
7562
+ # Test "AcquisitionDate" header name column is hidden
7563
+ self .assertTrue (input_filter .table_data .isColumnHidden (tag_col_idx ))
7584
7564
7585
- # Opens the "Visualized tags" pop up and adds the "AcquisitionDate" tag
7565
+ # Add "AcquisitionDate" as a visualized tag
7586
7566
QTimer .singleShot (
7587
7567
100 ,
7588
7568
lambda : self .add_visualized_tag (
@@ -7591,29 +7571,64 @@ def test_filter_widget(self):
7591
7571
)
7592
7572
input_filter .update_tags ()
7593
7573
7594
- # FIXME: The following statement is always True (not the correct test)
7595
- self .assertTrue (
7596
- type (input_filter .table_data .get_tag_column ("AcquisitionDate" ))
7597
- == int
7598
- )
7574
+ # Test "AcquisitionDate" header name column is not hidden
7575
+ self .assertFalse (input_filter .table_data .isColumnHidden (tag_col_idx ))
7576
+
7577
+ # Mock selection of the tag to filter
7578
+ def create_mock_exec (tag_name ):
7579
+ """
7580
+ Create a mock function for PopUpSelectTagCountTable.exec_() that
7581
+ simulates user tag selection behavior.
7582
+
7583
+ This function returns a mock implementation that programmatically
7584
+ selects a specific tag from the popup's list widget and triggers
7585
+ the OK action, simulating the user workflow without requiring
7586
+ actual UI interaction.
7587
+
7588
+ :param tag_name (str): The name of the tag to select from the
7589
+ list. This should match the text of one of
7590
+ the items in the popup's list widget.
7591
+
7592
+ :return: A mock function that can be used to replace exec_()
7593
+ method.
7594
+ """
7595
+
7596
+ def mock_exec (self ):
7597
+ """
7598
+ Mock implementation of exec_() that simulates tag selection.
7599
+
7600
+ Searches through the popup's list widget for an item with text
7601
+ matching the specified tag name, checks it, and calls
7602
+ ok_clicked() to simulate the user confirming their selection.
7603
+
7604
+ :param self: The PopUpSelectTagCountTable instance
7605
+
7606
+ :return: True to simulate successful dialog execution
7607
+ """
7608
+ # Find and select the specific tag
7609
+ for i in range (self .list_widget_tags .count ()):
7610
+ item = self .list_widget_tags .item (i )
7611
+
7612
+ if item .text () == tag_name :
7613
+ item .setCheckState (Qt .Checked )
7614
+ break
7615
+
7616
+ self .ok_clicked ()
7617
+ return True
7618
+
7619
+ return mock_exec
7599
7620
7600
- # Updates the tag to filter with
7601
7621
with patch .object (
7602
- PopUpSelectTagCountTable , "exec_" , return_value = True
7622
+ PopUpSelectTagCountTable , "exec_" , create_mock_exec ( TAG_FILENAME )
7603
7623
):
7604
7624
input_filter .update_tag_to_filter ()
7605
7625
7606
- input_filter .push_button_tag_filter .setText (TAG_FILENAME )
7607
- # TODO: select tag to filter with
7608
-
7609
- # Closes the filter
7610
- input_filter .ok_clicked ()
7626
+ input_filter .ok_clicked () # Close widget
7611
7627
7612
- # Switches back to node controller V2, if necessary (return to initial
7613
- # state)
7628
+ # Restore controller to V2 if needed
7614
7629
config = Config (properties_path = self .properties_path )
7615
7630
7616
- if not controlV1_ver :
7631
+ if not controlV1 :
7617
7632
config .setControlV1 (False )
7618
7633
7619
7634
def test_node_controller (self ):
0 commit comments