Skip to content

Commit 30c9e67

Browse files
committed
OWMergeData: Improve test coverage
1 parent 4f6ac7d commit 30c9e67

File tree

2 files changed

+120
-3
lines changed

2 files changed

+120
-3
lines changed

Orange/widgets/data/owmergedata.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -584,13 +584,20 @@ def prepare(arr, inds, str_cols):
584584

585585
@staticmethod
586586
def migrate_settings(settings, version=None):
587+
def mig_value(x):
588+
if x == "Position (index)":
589+
return INDEX
590+
if x == "Source position (index)":
591+
return INSTANCEID
592+
return x
593+
587594
if not version:
588595
operations = ("augment", "merge", "combine")
589-
oper = [settings["merging"]]
596+
oper = operations[settings["merging"]]
590597
settings["attr_pairs"] = (
591598
True, True,
592-
[(settings[f"attr_{oper}_data"],
593-
settings[f"attr_{oper}_extra"])])
599+
[(mig_value(settings[f"attr_{oper}_data"]),
600+
mig_value(settings[f"attr_{oper}_extra"]))])
594601
for oper in operations:
595602
del settings[f"attr_{oper}_data"]
596603
del settings[f"attr_{oper}_extra"]

Orange/widgets/data/tests/test_owmergedata.py

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import numpy as np
77
import scipy.sparse as sp
88

9+
from AnyQt.QtCore import Qt
10+
911
from Orange.data import Table, Domain, DiscreteVariable, StringVariable, \
1012
ContinuousVariable
1113
from 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

Comments
 (0)