def test_scrolling(): text = teek.Text(teek.Window()) asd = [] def callback(x, y): asd.extend([x, y]) text.config['yscrollcommand'].connect(callback) text.insert(text.end, 'toot\ntoot\n' * text.config['height']) # scroll to end, and make sure everything is visible text.yview('moveto', 1) text.pack() teek.update() # this fails consistently in travis for some reason, but if i run this # locally in xvfb-run, it works fine 0_o if 'CI' not in os.environ: assert round(asd[-2], 1) == 0.5 assert asd[-1] == 1.0 # yview return type checks assert text.yview('moveto', 1) is None pair = text.yview() assert isinstance(pair, tuple) and len(pair) == 2 assert all(isinstance(item, float) for item in pair)
def test_bind(handy_callback): widget = teek.Window() assert not widget.bindings.keys() @handy_callback def tcl_call_bound_callback(): pass @handy_callback def teek_bound_callback(): pass command = teek.create_command(tcl_call_bound_callback) teek.tcl_call(None, 'bind', widget, '<<Asd>>', command) assert widget.bindings.keys() == {'<<Asd>>'} widget.bind('<<Asd>>', teek_bound_callback) teek.update() teek.tcl_call(None, 'event', 'generate', widget, '<<Asd>>') teek.delete_command(command) assert tcl_call_bound_callback.ran_once() # tests binding with + assert teek_bound_callback.ran_once() # some binding strings are equivalent assert widget.bindings['<Button-3>'] is widget.bindings['<Button-3>'] assert widget.bindings['<3>'] is widget.bindings['<Button-3>'] assert repr(widget.bindings) == '<a bindings object, behaves like a dict>'
def test_image_doesnt_load_without_threads(): souper, widget = create_souped_widget(big_html, threads=False) assert 'firefox pic alt' in widget.get() end = time.time() + 0.5 while time.time() < end: teek.update() assert 'firefox pic alt' in widget.get()
def test_image_loads_with_threads(deinit_threads): teek.init_threads() souper, widget = create_souped_widget(big_html) # threads=True is default assert 'firefox pic alt' in widget.get() time.sleep(1) # this used to be 0.1 and it made tests fail randomly teek.update() assert 'firefox pic alt' not in widget.get()
def test_image_loads_with_threads(deinit_threads): teek.init_threads() souper, widget = create_souped_widget(big_html) # threads=True is default assert 'firefox pic alt' in widget.get() time.sleep(0.1) teek.update() assert 'firefox pic alt' not in widget.get()
def test_bind_break(): events = [] widget = teek.Window() widget.bind('<<Asd>>', (lambda: events.append('one'))) widget.bind('<<Asd>>', (lambda: [events.append('two'), 'break'][1])) # lol widget.bind('<<Asd>>', (lambda: events.append('three'))) teek.update() # needed for virtual events to work widget.event_generate('<<Asd>>')
def test_see(): text = teek.Text(teek.Window()) for i in range(1, 1000): text.insert(text.end, 'toot %d\n' % i) teek.update() yview1 = text.yview() text.see(text.end) teek.update() yview2 = text.yview() assert max(yview1) < 0.5 and min(yview2) > 0.5
def test_weird_error(capfd): # make sure that previous tests don't mess up teek.after_idle(teek.quit) teek.run() # ignore anything that ended up in the stderr because previous tests # TODO: why is stderr SOMETIMES non-empty?? capfd.readouterr() teek.create_command(print) # the command is intentionally not deleted teek.quit() teek.update() assert capfd.readouterr() == ('', '')
def test_destroy_event_bug(handy_callback): for gonna_update_in_between in [True, False]: frame = teek.Frame(teek.Window()) @handy_callback def on_destroy(): pass frame.bind('<Destroy>', on_destroy) if gonna_update_in_between: teek.update() frame.destroy() assert on_destroy.ran_once() teek.update()
def func(monkeypatch, handy_callback): @handy_callback def fake_run(): pass with monkeypatch.context() as monkey: monkey.setattr(teek, 'run', fake_run) exec(code, {'__file__': os.path.join(EXAMPLES_DIR, filename)}) assert fake_run.ran_once() # make sure that nothing breaks if the real .run() is called teek.update() teek.after_idle(teek.quit) teek.run()
def test_event_objects(): events = [] widget = teek.Window() widget.bind('<<Asd>>', events.append, event=True) teek.update() # needed for virtual events to work widget.event_generate('<<Asd>>', data='asd asd') event = events.pop() assert not events # if some of these checks fail, feel free to make them less strict assert event.data(str) == 'asd asd' assert event.above is None assert event.borderwidth is None assert event.button is None assert event.char == '??' assert event.count is None assert event.delta is None assert event.focus is None assert event.height is None assert isinstance(event.i_window, int) assert event.keycode is None assert event.keysym == '??' assert event.keysym_num is None assert event.mode == '??' assert event.override is None assert event.place == '??' assert event.property_name == '??' assert event.root == 0 assert event.rootx == -1 assert event.rooty == -1 assert event.sendevent is False assert isinstance(event.serial, int) assert event.state == '0' assert event.subwindow == 0 assert event.time == 0 assert event.type == 35 # see some docs somewhere i dunno why 35 assert event.widget is widget assert event.width is None assert event.x == 0 assert event.y == 0 regex = r"<Event: data='asd asd', serial=\d+, type=35>" assert re.fullmatch(regex, repr(event)) is not None
def test_winfo_x_y_rootx_rooty_width_height_reqwidth_reqheight(): # layout in the window looks like this: # ________ # | | # | | # | | # | |456px # | | # | | # |________|___ # 123px | a | # `---' window = teek.Window() spacer = teek.Frame(window, width=123, height=456) spacer.grid(row=1, column=1) label = teek.Label(window, text='a') label.grid(row=2, column=2) window.geometry(100, 200) teek.update() assert window.toplevel.winfo_x() == window.toplevel.winfo_rootx() assert window.toplevel.winfo_y() == window.toplevel.winfo_rooty() assert window.toplevel.winfo_width() == 100 assert window.toplevel.winfo_height() == 200 assert window.toplevel.winfo_reqwidth() > 123 assert window.toplevel.winfo_reqheight() > 456 assert spacer.winfo_x() == 0 assert spacer.winfo_y() == 0 assert spacer.winfo_rootx() == window.toplevel.winfo_x() assert spacer.winfo_rooty() == window.toplevel.winfo_y() assert spacer.winfo_width() == 123 assert spacer.winfo_height() == 456 assert spacer.winfo_reqwidth() == 123 assert spacer.winfo_reqheight() == 456 assert label.winfo_x() == 123 assert label.winfo_y() == 456 assert label.winfo_rootx() == window.toplevel.winfo_x() + 123 assert label.winfo_rooty() == window.toplevel.winfo_y() + 456 assert label.winfo_width() > 0 assert label.winfo_height() > 0 assert label.winfo_reqwidth() > 0 assert label.winfo_reqheight() > 0
def test_window(): windows = [ (teek.Window("hello hello"), "hello hello"), (teek.Window(), None), ] for window, default_title in windows: assert window.winfo_toplevel() is window.toplevel assert isinstance(window.toplevel, teek.Toplevel) teek.update() # you can add more of these if the tests don't work assert window.wm_state == 'normal' if default_title is not None: assert window.title == default_title assert repr(default_title) in repr(window) window.title = "hello hello" assert window.title == "hello hello" not_a_window = teek.Frame(teek.Window()) assert not hasattr(not_a_window, 'title')
def test_bind_class(handy_callback): @handy_callback def class_callback(): pass @handy_callback def all_callback(): pass teek.Text.bind_class('<<Lol>>', class_callback) teek.Widget.bind_class('<<Lol>>', all_callback) text = teek.Text(teek.Window()) text.pack() teek.update() # make sure that virtual events work text.event_generate('<<Lol>>') assert class_callback.ran_once() assert all_callback.ran_once() class FunnyWidget(teek.Widget): pass with pytest.raises(AttributeError) as error: text.class_bindings assert str(error.value) == ( "the class_bindings attribute must be used like Text.class_bindings, " "not like some_text_instance.class_bindings") with pytest.raises(AttributeError) as error2: FunnyWidget.class_bindings with pytest.raises(AttributeError) as error3: FunnyWidget.bind_class('<<Lol>>', print) assert str(error2.value) == str(error3.value) == ( "FunnyWidget cannot be used with class_bindings and bind_class()")
def test_window_states(): window = teek.Window() for method, state in [(window.withdraw, 'withdrawn'), (window.iconify, 'iconic')]: method() teek.update() assert window.wm_state == state assert ("wm_state='%s'" % state) in repr(window) window.deiconify() teek.update() assert window.wm_state == 'normal' assert "wm_state='normal'" not in repr(window) window.wm_state = state # should do same as method() teek.update() assert window.wm_state == state window.deiconify() teek.update() assert window.wm_state == 'normal'
def test_winfo_ismapped(): window = teek.Window() teek.update() assert window.winfo_ismapped() is True frame = teek.Frame(window) assert frame.winfo_ismapped() is False teek.update() assert frame.winfo_ismapped() is False frame.pack() teek.update() assert frame.winfo_ismapped() is True
def test_geometry_changes(): window = teek.Window() window.geometry(300, 400) teek.update() assert window.geometry()[:2] == (300, 400) window.geometry(x=123, y=456) teek.update() assert window.geometry() == (300, 400, 123, 456) window.geometry(100, 200, 300, 400) teek.update() assert window.geometry() == (100, 200, 300, 400)
def run_event_loop(for_how_long): # this is dumb start = time.time() while time.time() < start + for_how_long: teek.update()
def test_update_idletasks(fake_command): with fake_command('update') as called: teek.update(idletasks_only=True) assert called == [['idletasks']]