1import libqtile.config 2from libqtile.bar import Bar 3from libqtile.widget.check_updates import CheckUpdates, Popen # noqa: F401 4 5 6def no_op(*args, **kwargs): 7 pass 8 9 10wrong_distro = "Barch" 11good_distro = "Arch" 12cmd_0_line = "export toto" # quick "monkeypatch" simulating 0 output, ie 0 update 13cmd_1_line = "echo toto" # quick "monkeypatch" simulating 1 output, ie 1 update 14cmd_error = "false" 15nus = "No Update Avalaible" 16 17 18def test_unknown_distro(): 19 """ test an unknown distribution """ 20 cu = CheckUpdates(distro=wrong_distro) 21 text = cu.poll() 22 assert text == "N/A" 23 24 25def test_update_available(fake_qtile, fake_window): 26 """ test output with update (check number of updates and color) """ 27 cu2 = CheckUpdates(distro=good_distro, 28 custom_command=cmd_1_line, 29 colour_have_updates="#123456" 30 ) 31 fakebar = Bar([cu2], 24) 32 fakebar.window = fake_window 33 fakebar.width = 10 34 fakebar.height = 10 35 fakebar.draw = no_op 36 cu2._configure(fake_qtile, fakebar) 37 text = cu2.poll() 38 assert text == "Updates: 1" 39 assert cu2.layout.colour == cu2.colour_have_updates 40 41 42def test_no_update_available_without_no_update_string(fake_qtile, fake_window): 43 """ test output with no update (without dedicated string nor color) """ 44 cu3 = CheckUpdates(distro=good_distro, custom_command=cmd_0_line) 45 fakebar = Bar([cu3], 24) 46 fakebar.window = fake_window 47 fakebar.width = 10 48 fakebar.height = 10 49 fakebar.draw = no_op 50 cu3._configure(fake_qtile, fakebar) 51 text = cu3.poll() 52 assert text == "" 53 54 55def test_no_update_available_with_no_update_string_and_color_no_updates( 56 fake_qtile, fake_window 57): 58 """ test output with no update (with dedicated string and color) """ 59 cu4 = CheckUpdates(distro=good_distro, 60 custom_command=cmd_0_line, 61 no_update_string=nus, 62 colour_no_updates="#654321" 63 ) 64 fakebar = Bar([cu4], 24) 65 fakebar.window = fake_window 66 fakebar.width = 10 67 fakebar.height = 10 68 fakebar.draw = no_op 69 cu4._configure(fake_qtile, fakebar) 70 text = cu4.poll() 71 assert text == nus 72 assert cu4.layout.colour == cu4.colour_no_updates 73 74 75def test_update_available_with_restart_indicator(monkeypatch, fake_qtile, fake_window): 76 """ test output with no indicator where restart needed """ 77 cu5 = CheckUpdates(distro=good_distro, 78 custom_command=cmd_1_line, 79 restart_indicator="*", 80 ) 81 monkeypatch.setattr("os.path.exists", lambda x: True) 82 fakebar = Bar([cu5], 24) 83 fakebar.window = fake_window 84 fakebar.width = 10 85 fakebar.height = 10 86 fakebar.draw = no_op 87 cu5._configure(fake_qtile, fakebar) 88 text = cu5.poll() 89 assert text == "Updates: 1*" 90 91 92def test_update_available_with_execute(manager_nospawn, minimal_conf_noscreen, monkeypatch): 93 """ test polling after executing command """ 94 95 # Use monkeypatching to patch both Popen (for execute command) and call_process 96 97 # This class returns None when first polled (to simulate that the task is still running) 98 # and then 0 on the second call. 99 class MockPopen: 100 def __init__(self, *args, **kwargs): 101 self.call_count = 0 102 103 def poll(self): 104 if self.call_count == 0: 105 self.call_count += 1 106 return None 107 return 0 108 109 # Bit of an ugly hack to replicate the above functionality but for a method. 110 class MockSpawn: 111 call_count = 0 112 113 @classmethod 114 def call_process(cls, *args, **kwargs): 115 if cls.call_count == 0: 116 cls.call_count += 1 117 return "Updates" 118 return "" 119 120 cu6 = CheckUpdates(distro=good_distro, 121 custom_command="dummy", 122 execute="dummy", 123 no_update_string=nus, 124 ) 125 126 # Patch the necessary object 127 monkeypatch.setattr(cu6, "call_process", MockSpawn.call_process) 128 monkeypatch.setattr("libqtile.widget.check_updates.Popen", MockPopen) 129 130 config = minimal_conf_noscreen 131 config.screens = [ 132 libqtile.config.Screen( 133 top=libqtile.bar.Bar([cu6], 10) 134 ) 135 ] 136 137 manager_nospawn.start(config) 138 139 topbar = manager_nospawn.c.bar["top"] 140 141 assert topbar.info()["widgets"][0]["text"] == "Updates: 1" 142 143 # Clicking the widget triggers the execute command 144 topbar.fake_button_press(0, "top", 0, 0, button=1) 145 146 # The second time we poll the widget, the update process is complete 147 # and there are no more updates 148 _, result = manager_nospawn.c.widget["checkupdates"].eval("self.poll()") 149 assert result == nus 150 151 152def test_update_process_error(fake_qtile, fake_window): 153 """ test output where update check gives error""" 154 cu7 = CheckUpdates(distro=good_distro, 155 custom_command=cmd_error, 156 no_update_string="ERROR", 157 ) 158 fakebar = Bar([cu7], 24) 159 fakebar.window = fake_window 160 fakebar.width = 10 161 fakebar.height = 10 162 fakebar.draw = no_op 163 cu7._configure(fake_qtile, fakebar) 164 text = cu7.poll() 165 assert text == "ERROR" 166 167 168def test_line_truncations(fake_qtile, monkeypatch, fake_window): 169 """ test update count is reduced""" 170 171 # Mock output to return 5 lines of text 172 def mock_process(*args, **kwargs): 173 return "1\n2\n3\n4\n5\n" 174 175 # Fedora is set up to remove 1 from line count 176 cu8 = CheckUpdates(distro="Fedora") 177 178 monkeypatch.setattr(cu8, "call_process", mock_process) 179 fakebar = Bar([cu8], 24) 180 fakebar.window = fake_window 181 fakebar.width = 10 182 fakebar.height = 10 183 fakebar.draw = no_op 184 cu8._configure(fake_qtile, fakebar) 185 text = cu8.poll() 186 187 # Should have 4 updates 188 assert text == "Updates: 4" 189