66import numpy as np
77import scipy .sparse as sp
88
9+ from AnyQt .QtCore import Qt
10+
911from Orange .data import Table , Domain , DiscreteVariable , StringVariable , \
1012 ContinuousVariable
1113from Orange .widgets .data .owmergedata import OWMergeData , INSTANCEID , INDEX
@@ -109,6 +111,25 @@ def test_combo_box_sync(self):
109111 self .assertEqual (data_combo .currentIndex (), 1 )
110112 self .assertEqual (extra_combo .currentIndex (), 1 )
111113
114+ def test_attr_combo_tooltips (self ):
115+ row = self .widget .attr_boxes .rows [0 ]
116+ model = row .left_combo .model ()
117+ self .send_signal (self .widget .Inputs .data , self .dataA )
118+ self .send_signal (self .widget .Inputs .extra_data , self .dataA )
119+
120+ tip = model .data (model .index (2 , 0 ), Qt .ToolTipRole )
121+ # Test the test; if general tooltips ever change and the following
122+ # assert fails, the rest of this test has to be modified accordingly
123+ self .assertTrue (tip .startswith ("<b>" ))
124+
125+ # Just test that tooltip is a string (implicitly) and that it's not
126+ # a generic DomainModel tooltip
127+ tip = model .data (model .index (0 , 0 ), Qt .ToolTipRole )
128+ self .assertFalse (tip .startswith ("<b>" ))
129+
130+ tip = model .data (model .index (1 , 0 ), Qt .ToolTipRole )
131+ self .assertFalse (tip .startswith ("<b>" ))
132+
112133 def test_match_attr_name (self ):
113134 widget = self .widget
114135 row = widget .attr_boxes .rows [0 ]
@@ -235,6 +256,13 @@ def test_remove_row(self):
235256 self .assertEqual (row .add_button .isEnabled (), i == 1 )
236257 self .assertEqual (row .add_button .text (), ["" , "+" ][i == 1 ])
237258
259+ def test_dont_remove_single_row (self ):
260+ widget = self .widget
261+ rows = widget .attr_boxes .rows
262+ self .assertEqual (len (rows ), 1 )
263+ rows [0 ].remove_button .clicked .emit ()
264+ self .assertEqual (len (rows ), 1 )
265+
238266 def test_retrieve_settings (self ):
239267 widget = self .widget
240268 boxes = widget .attr_boxes
@@ -258,6 +286,71 @@ def test_retrieve_settings(self):
258286 widget2 .attr_boxes .current_state (),
259287 [(INDEX , INDEX ), (INSTANCEID , INSTANCEID ), (var0 , var1 )])
260288
289+ def test_retrieve_settings_with_missing_var (self ):
290+ widget = self .widget
291+ boxes = widget .attr_boxes
292+ var0 , var1 = self .dataA .domain .attributes [:2 ]
293+
294+ self .send_signal (self .widget .Inputs .data , self .dataA )
295+ self .send_signal (self .widget .Inputs .extra_data , self .dataA )
296+
297+ boxes .set_state (
298+ [(INDEX , INDEX ), (INSTANCEID , INSTANCEID ), (var0 , var1 )])
299+
300+ domain = self .dataA .domain
301+
302+ # The left combo in the last row must change to INDEX due to missing var
303+ data2 = self .dataA .transform (
304+ Domain (domain .attributes [1 :], domain .class_var , domain .metas ))
305+ settings = widget .settingsHandler .pack_data (widget )
306+ widget2 = self .create_widget (OWMergeData , stored_settings = settings )
307+ widget2 .attr_boxes .set_state ([(INDEX , INDEX )])
308+ self .send_signals (
309+ [(widget2 .Inputs .data , data2 ),
310+ (widget2 .Inputs .extra_data , data2 )],
311+ widget = widget2 )
312+ self .assertEqual (
313+ widget2 .attr_boxes .current_state (),
314+ [(INDEX , INDEX ), (INSTANCEID , INSTANCEID ), (INDEX , var1 )])
315+
316+ # The last row is changed to INDEX, INDEX and removed as duplicate
317+ data2 = self .dataA .transform (
318+ Domain (domain .attributes [2 :], domain .class_var , domain .metas ))
319+ settings = widget .settingsHandler .pack_data (widget )
320+ widget2 = self .create_widget (OWMergeData , stored_settings = settings )
321+ widget2 .attr_boxes .set_state ([(INDEX , INDEX )])
322+ self .send_signals (
323+ [(widget2 .Inputs .data , data2 ),
324+ (widget2 .Inputs .extra_data , data2 )],
325+ widget = widget2 )
326+ self .assertEqual (
327+ widget2 .attr_boxes .current_state (),
328+ [(INDEX , INDEX ), (INSTANCEID , INSTANCEID )])
329+
330+ def test_migrate_settings (self ):
331+ attr1 , attr2 , attr3 , attr4 , attr5 = [object () for _ in range (5 )]
332+ orig_settings = dict (
333+ attr_augment_data = attr1 , attr_augment_extra = attr2 ,
334+ attr_merge_data = attr3 , attr_merge_extra = attr4 ,
335+ attr_combine_data = attr5 , attr_combine_extra = 'Position (index)' )
336+
337+ widget = self .create_widget (
338+ OWMergeData , stored_settings = dict (merging = 0 , ** orig_settings ))
339+ self .assertEqual (widget .attr_pairs , (True , True , [(attr1 , attr2 )]))
340+
341+ widget = self .create_widget (
342+ OWMergeData , stored_settings = dict (merging = 1 , ** orig_settings ))
343+ self .assertEqual (widget .attr_pairs , (True , True , [(attr3 , attr4 )]))
344+
345+ widget = self .create_widget (
346+ OWMergeData , stored_settings = dict (merging = 2 , ** orig_settings ))
347+ self .assertEqual (widget .attr_pairs , (True , True , [(attr5 , INDEX )]))
348+
349+ orig_settings ["attr_combine_extra" ] = "Source position (index)"
350+ widget = self .create_widget (
351+ OWMergeData , stored_settings = dict (merging = 2 , ** orig_settings ))
352+ self .assertEqual (widget .attr_pairs , (True , True , [(attr5 , INSTANCEID )]))
353+
261354 @unittest .skip ("widget doesn't work this way, but could in the future" )
262355 def test_switch_domain (self ): # pragma: no cover
263356 widget = self .widget
@@ -322,6 +415,23 @@ def test_report(self):
322415 widget .send_report ()
323416 # Don't crash, that's it
324417
418+ def test_no_matches (self ):
419+ """Check output is None when there are no matches in inner join"""
420+ self .send_signal (self .widget .Inputs .data , self .dataA )
421+ self .send_signal (self .widget .Inputs .extra_data , self .dataB )
422+ domA = self .dataA .domain
423+ domB = self .dataB .domain
424+
425+ self .widget .attr_boxes .set_state ([(domA ["dA1" ], domB ["dB2" ])])
426+ self .widget .controls .merging .buttons [self .widget .LeftJoin ].click ()
427+ self .assertIsNotNone (self .get_output (self .widget .Outputs .data ))
428+
429+ self .widget .controls .merging .buttons [self .widget .InnerJoin ].click ()
430+ self .assertIsNone (self .get_output (self .widget .Outputs .data ))
431+
432+ self .widget .controls .merging .buttons [self .widget .OuterJoin ].click ()
433+ self .assertIsNotNone (self .get_output (self .widget .Outputs .data ))
434+
325435 def test_output_merge_by_ids_inner (self ):
326436 """Check output for merging option 'Find matching rows' by
327437 Source position (index)"""
0 commit comments