@@ -1542,6 +1542,192 @@ def test_entryconfigure_variable(self): |
1542 | 1542 | m1.entryconfigure(1, variable=v2) |
1543 | 1543 | self.assertEqual(str(m1.entrycget(1, 'variable')), str(v2)) |
1544 | 1544 |
|
| 1545 | + def test_add(self): |
| 1546 | + m = self.create(tearoff=False) |
| 1547 | + m.add_command(label='Command') |
| 1548 | + m.add_checkbutton(label='Checkbutton') |
| 1549 | + m.add_radiobutton(label='Radiobutton') |
| 1550 | + m.add_separator() |
| 1551 | + m.add_cascade(label='Cascade', menu=tkinter.Menu(m, tearoff=False)) |
| 1552 | + self.assertEqual(m.index('end'), 4) |
| 1553 | + self.assertEqual([m.type(i) for i in range(5)], |
| 1554 | + ['command', 'checkbutton', 'radiobutton', |
| 1555 | + 'separator', 'cascade']) |
| 1556 | + self.assertEqual(m.entrycget(0, 'label'), 'Command') |
| 1557 | + self.assertRaisesRegex(TclError, 'bad menu entry type "spam"', |
| 1558 | + m.add, 'spam') |
| 1559 | + |
| 1560 | + def test_insert(self): |
| 1561 | + m = self.create(tearoff=False) |
| 1562 | + m.add_command(label='A') |
| 1563 | + m.add_command(label='C') |
| 1564 | + m.insert_command(1, label='B') |
| 1565 | + m.insert_separator(0) |
| 1566 | + m.insert_checkbutton('end', label='D') |
| 1567 | + m.insert_radiobutton(0, label='top') |
| 1568 | + m.insert_cascade(2, label='sub', |
| 1569 | + menu=tkinter.Menu(m, tearoff=False)) |
| 1570 | + self.assertEqual( |
| 1571 | + [m.type(i) for i in range(m.index('end') + 1)], |
| 1572 | + ['radiobutton', 'separator', 'cascade', 'command', |
| 1573 | + 'command', 'command', 'checkbutton']) |
| 1574 | + self.assertEqual( |
| 1575 | + [m.entrycget(i, 'label') for i in (3, 4, 5)], |
| 1576 | + ['A', 'B', 'C']) |
| 1577 | + self.assertRaisesRegex(TclError, 'bad menu entry type "spam"', |
| 1578 | + m.insert, 0, 'spam') |
| 1579 | + self.assertRaisesRegex(TclError, 'bad menu entry index "spam"', |
| 1580 | + m.insert_command, 'spam', label='z') |
| 1581 | + |
| 1582 | + def test_delete(self): |
| 1583 | + m = self.create(tearoff=False) |
| 1584 | + commands = [] |
| 1585 | + for label in 'ABCDE': |
| 1586 | + m.add_command(label=label, |
| 1587 | + command=lambda label=label: commands.append(label)) |
| 1588 | + # The Tcl command for a deleted item is cleaned up. |
| 1589 | + funcid = str(m.entrycget(2, 'command')) |
| 1590 | + self.assertEqual( |
| 1591 | + m.tk.splitlist(m.tk.call('info', 'commands', funcid)), (funcid,)) |
| 1592 | + |
| 1593 | + m.delete(2) # Delete a single item ('C'). |
| 1594 | + self.assertEqual([m.entrycget(i, 'label') for i in range(4)], |
| 1595 | + ['A', 'B', 'D', 'E']) |
| 1596 | + self.assertEqual( |
| 1597 | + m.tk.splitlist(m.tk.call('info', 'commands', funcid)), ()) |
| 1598 | + |
| 1599 | + m.delete(1, 2) # Delete a range ('B' and 'D'). |
| 1600 | + self.assertEqual([m.entrycget(i, 'label') for i in range(2)], |
| 1601 | + ['A', 'E']) |
| 1602 | + self.assertRaises(TypeError, m.delete) |
| 1603 | + |
| 1604 | + def test_index(self): |
| 1605 | + m = self.create(tearoff=False) |
| 1606 | + self.assertIsNone(m.index('end')) |
| 1607 | + m.add_command(label='First') |
| 1608 | + m.add_command(label='Second') |
| 1609 | + self.assertEqual(m.index('end'), 1) |
| 1610 | + self.assertEqual(m.index('last'), 1) |
| 1611 | + self.assertEqual(m.index('Second'), 1) |
| 1612 | + self.assertEqual(m.index(0), 0) |
| 1613 | + # 'active' and 'none' map to None when no item is active. |
| 1614 | + self.assertIsNone(m.index('active')) |
| 1615 | + self.assertIsNone(m.index('none')) |
| 1616 | + self.assertRaisesRegex(TclError, 'bad menu entry index "spam"', |
| 1617 | + m.index, 'spam') |
| 1618 | + |
| 1619 | + def test_invoke(self): |
| 1620 | + m = self.create(tearoff=False) |
| 1621 | + commands = [] |
| 1622 | + m.add_command(label='Command', |
| 1623 | + command=lambda: commands.append('invoked')) |
| 1624 | + var = tkinter.IntVar(self.root) |
| 1625 | + m.add_checkbutton(label='Check', variable=var, |
| 1626 | + onvalue=1, offvalue=0) |
| 1627 | + rvar = tkinter.StringVar(self.root) |
| 1628 | + m.add_radiobutton(label='Radio', variable=rvar, value='on') |
| 1629 | + |
| 1630 | + m.invoke(0) |
| 1631 | + self.assertEqual(commands, ['invoked']) |
| 1632 | + m.invoke(1) |
| 1633 | + self.assertEqual(var.get(), 1) |
| 1634 | + m.invoke(1) |
| 1635 | + self.assertEqual(var.get(), 0) |
| 1636 | + m.invoke(2) |
| 1637 | + self.assertEqual(rvar.get(), 'on') |
| 1638 | + self.assertRaisesRegex(TclError, 'bad menu entry index "spam"', |
| 1639 | + m.invoke, 'spam') |
| 1640 | + |
| 1641 | + def test_xposition_yposition(self): |
| 1642 | + m = self.create(tearoff=False) |
| 1643 | + m.add_command(label='First') |
| 1644 | + m.add_command(label='Second') |
| 1645 | + m.update_idletasks() |
| 1646 | + self.assertIsInstance(m.xposition(0), int) |
| 1647 | + y0 = m.yposition(0) |
| 1648 | + y1 = m.yposition(1) |
| 1649 | + self.assertIsInstance(y0, int) |
| 1650 | + self.assertLess(y0, y1) |
| 1651 | + # An out-of-range index gives the position past the last item. |
| 1652 | + self.assertEqual(m.xposition('end'), m.xposition(1)) |
| 1653 | + self.assertRaisesRegex(TclError, 'bad menu entry index "spam"', |
| 1654 | + m.xposition, 'spam') |
| 1655 | + self.assertRaisesRegex(TclError, 'bad menu entry index "spam"', |
| 1656 | + m.yposition, 'spam') |
| 1657 | + |
| 1658 | + def test_post_unpost(self): |
| 1659 | + m = self.create(tearoff=False) |
| 1660 | + if m._windowingsystem != 'x11': |
| 1661 | + # Posting a menu is modal on Windows and uses a native, unmapped |
| 1662 | + # menu on Aqua, so it cannot be tested synchronously there. |
| 1663 | + self.skipTest('menu posting is not testable on this platform') |
| 1664 | + m.add_command(label='First') |
| 1665 | + m.add_command(label='Second') |
| 1666 | + self.assertFalse(m.winfo_ismapped()) |
| 1667 | + |
| 1668 | + m.post(0, 0) |
| 1669 | + m.update() |
| 1670 | + self.assertTrue(m.winfo_ismapped()) |
| 1671 | + m.unpost() |
| 1672 | + m.update() |
| 1673 | + self.assertFalse(m.winfo_ismapped()) |
| 1674 | + |
| 1675 | + m.tk_popup(0, 0) |
| 1676 | + m.update() |
| 1677 | + self.assertTrue(m.winfo_ismapped()) |
| 1678 | + m.unpost() |
| 1679 | + m.update() |
| 1680 | + self.assertFalse(m.winfo_ismapped()) |
| 1681 | + |
| 1682 | + def check_entry_option(self, m, index, option, value, expected=None): |
| 1683 | + if expected is None: |
| 1684 | + expected = value |
| 1685 | + m.entryconfigure(index, **{option: value}) |
| 1686 | + self.assertEqual(str(m.entrycget(index, option)), str(expected)) |
| 1687 | + self.assertEqual(str(m.entryconfigure(index, option)[4]), str(expected)) |
| 1688 | + |
| 1689 | + def test_entry_options(self): |
| 1690 | + m = self.create(tearoff=False) |
| 1691 | + m.add_command(label='Command') |
| 1692 | + self.check_entry_option(m, 0, 'accelerator', 'Ctrl+O') |
| 1693 | + self.check_entry_option(m, 0, 'underline', 2) |
| 1694 | + self.check_entry_option(m, 0, 'state', 'disabled') |
| 1695 | + self.check_entry_option(m, 0, 'background', 'red') |
| 1696 | + self.check_entry_option(m, 0, 'foreground', 'blue') |
| 1697 | + self.check_entry_option(m, 0, 'columnbreak', 1) |
| 1698 | + self.check_entry_option(m, 0, 'hidemargin', 1) |
| 1699 | + |
| 1700 | + m.add_checkbutton(label='Checkbutton') |
| 1701 | + self.check_entry_option(m, 1, 'onvalue', 'Y') |
| 1702 | + self.check_entry_option(m, 1, 'offvalue', 'N') |
| 1703 | + self.check_entry_option(m, 1, 'indicatoron', 0) |
| 1704 | + |
| 1705 | + m.add_radiobutton(label='Radiobutton') |
| 1706 | + self.check_entry_option(m, 2, 'value', 'V') |
| 1707 | + self.check_entry_option(m, 2, 'selectcolor', 'green') |
| 1708 | + |
| 1709 | + def test_entry_options_invalid(self): |
| 1710 | + m = self.create(tearoff=False) |
| 1711 | + m.add_command(label='Command') |
| 1712 | + self.assertRaisesRegex(TclError, 'unknown option "-spam"', |
| 1713 | + m.entrycget, 0, 'spam') |
| 1714 | + self.assertRaisesRegex(TclError, 'unknown option "-spam"', |
| 1715 | + m.entryconfigure, 0, spam='x') |
| 1716 | + self.assertRaisesRegex(TclError, 'bad state "spam"', |
| 1717 | + m.entryconfigure, 0, state='spam') |
| 1718 | + # Tk < 9 reports "expected integer but got ...", while Tk 9, where |
| 1719 | + # underline accepts an index, reports "bad index ...". |
| 1720 | + self.assertRaisesRegex(TclError, |
| 1721 | + r'(expected integer but got|bad index) "spam"', |
| 1722 | + m.entryconfigure, 0, underline='spam') |
| 1723 | + self.assertRaisesRegex(TclError, 'unknown color name "spam"', |
| 1724 | + m.entryconfigure, 0, background='spam') |
| 1725 | + self.assertRaisesRegex(TclError, 'expected boolean value but got "spam"', |
| 1726 | + m.entryconfigure, 0, columnbreak='spam') |
| 1727 | + # onvalue applies only to checkbutton and radiobutton entries. |
| 1728 | + self.assertRaisesRegex(TclError, 'unknown option "-onvalue"', |
| 1729 | + m.entrycget, 0, 'onvalue') |
| 1730 | + |
1545 | 1731 |
|
1546 | 1732 | @add_configure_tests(PixelSizeTests, StandardOptionsTests) |
1547 | 1733 | class MessageTest(AbstractWidgetTest, unittest.TestCase): |
|