qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

test_cli_commands.py (14256B)


      1 import platform
      2 from subprocess import DEVNULL
      3 
      4 from milc import cli
      5 
      6 is_windows = 'windows' in platform.platform().lower()
      7 
      8 
      9 def check_subcommand(command, *args):
     10     cmd = ['qmk', command, *args]
     11     result = cli.run(cmd, stdin=DEVNULL, combined_output=True)
     12     return result
     13 
     14 
     15 def check_subcommand_stdin(file_to_read, command, *args):
     16     """Pipe content of a file to a command and return output.
     17     """
     18     with open(file_to_read, encoding='utf-8') as my_file:
     19         cmd = ['qmk', command, *args]
     20         result = cli.run(cmd, stdin=my_file, combined_output=True)
     21     return result
     22 
     23 
     24 def check_returncode(result, expected=[0]):
     25     """Print stdout if `result.returncode` does not match `expected`.
     26     """
     27     if result.returncode not in expected:
     28         print('`%s` stdout:' % ' '.join(result.args))
     29         print(result.stdout)
     30         print('returncode:', result.returncode)
     31     assert result.returncode in expected
     32 
     33 
     34 def test_format_c():
     35     result = check_subcommand('format-c', '-n', 'quantum/matrix.c')
     36     check_returncode(result)
     37 
     38 
     39 def test_format_c_all():
     40     result = check_subcommand('format-c', '-n', '-a')
     41     check_returncode(result, [0, 1])
     42 
     43 
     44 def test_compile():
     45     result = check_subcommand('compile', '-kb', 'handwired/pytest/basic', '-km', 'default', '-n')
     46     check_returncode(result)
     47 
     48 
     49 def test_compile_json():
     50     result = check_subcommand('compile', '-kb', 'handwired/pytest/basic', '-km', 'default_json', '-n')
     51     check_returncode(result)
     52 
     53 
     54 def test_flash():
     55     result = check_subcommand('flash', '-kb', 'handwired/pytest/basic', '-km', 'default', '-n')
     56     check_returncode(result)
     57 
     58 
     59 def test_flash_bootloaders():
     60     result = check_subcommand('flash', '-b')
     61     check_returncode(result, [1])
     62 
     63 
     64 def test_kle2json():
     65     result = check_subcommand('kle2json', 'lib/python/qmk/tests/kle.txt', '-f')
     66     check_returncode(result)
     67     assert 'Wrote out' in result.stdout
     68 
     69 
     70 def test_doctor():
     71     result = check_subcommand('doctor', '-n')
     72     check_returncode(result, [0, 1])
     73     assert 'QMK Doctor is checking your environment.' in result.stdout
     74     assert 'QMK is ready to go' in result.stdout
     75 
     76 
     77 def test_hello():
     78     result = check_subcommand('hello')
     79     check_returncode(result)
     80     assert 'Hello,' in result.stdout
     81 
     82 
     83 def test_format_python():
     84     result = check_subcommand('format-python', '-n', '-a')
     85     check_returncode(result)
     86     assert 'Successfully formatted the python code.' in result.stdout
     87 
     88 
     89 def test_list_keyboards():
     90     result = check_subcommand('list-keyboards')
     91     check_returncode(result)
     92     # check to see if a known keyboard is returned
     93     # this will fail if handwired/pytest/basic is removed
     94     assert 'handwired/pytest/basic' in result.stdout
     95 
     96 
     97 def test_list_keymaps():
     98     result = check_subcommand('list-keymaps', '-kb', 'handwired/pytest/basic')
     99     check_returncode(result)
    100     assert 'default' in result.stdout
    101     assert 'default_json' in result.stdout
    102 
    103 
    104 def test_list_keymaps_long():
    105     result = check_subcommand('list-keymaps', '--keyboard', 'handwired/pytest/basic')
    106     check_returncode(result)
    107     assert 'default' in result.stdout
    108     assert 'default_json' in result.stdout
    109 
    110 
    111 def test_list_keymaps_community():
    112     result = check_subcommand('list-keymaps', '--keyboard', 'handwired/pytest/has_community')
    113     check_returncode(result)
    114     assert 'test' in result.stdout
    115 
    116 
    117 def test_list_keymaps_kb_only():
    118     result = check_subcommand('list-keymaps', '-kb', 'contra')
    119     check_returncode(result)
    120     assert 'default' in result.stdout
    121 
    122 
    123 def test_list_keymaps_vendor_kb():
    124     result = check_subcommand('list-keymaps', '-kb', 'ai03/lunar')
    125     check_returncode(result)
    126     assert 'default' in result.stdout
    127 
    128 
    129 def test_list_keymaps_vendor_kb_rev():
    130     result = check_subcommand('list-keymaps', '-kb', 'kbdfans/kbd67/mkiirgb/v2')
    131     check_returncode(result)
    132     assert 'default' in result.stdout
    133 
    134 
    135 def test_list_keymaps_no_keyboard_found():
    136     result = check_subcommand('list-keymaps', '-kb', 'asdfghjkl')
    137     check_returncode(result, [2])
    138     assert 'invalid keyboard_folder value' in result.stdout
    139 
    140 
    141 def test_json2c():
    142     result = check_subcommand('json2c', 'keyboards/handwired/pytest/basic/keymaps/default_json/keymap.json')
    143     check_returncode(result)
    144     assert result.stdout == """#include QMK_KEYBOARD_H
    145 #if __has_include("keymap.h")
    146 #    include "keymap.h"
    147 #endif
    148 
    149 
    150 /* THIS FILE WAS GENERATED!
    151  *
    152  * This file was generated by qmk json2c. You may or may not want to
    153  * edit it directly.
    154  */
    155 
    156 const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    157     [0] = LAYOUT_ortho_1x1(KC_A)
    158 };
    159 
    160 
    161 
    162 
    163 #ifdef OTHER_KEYMAP_C
    164 #    include OTHER_KEYMAP_C
    165 #endif // OTHER_KEYMAP_C
    166 
    167 
    168 """
    169 
    170 
    171 def test_json2c_macros():
    172     result = check_subcommand("json2c", 'keyboards/handwired/pytest/macro/keymaps/default/keymap.json')
    173     check_returncode(result)
    174     assert 'LAYOUT_ortho_1x1(QK_MACRO_0)' in result.stdout
    175     assert 'case QK_MACRO_0:' in result.stdout
    176     assert 'SEND_STRING("Hello, World!"SS_TAP(X_ENTER));' in result.stdout
    177 
    178 
    179 def test_json2c_stdin():
    180     result = check_subcommand_stdin('keyboards/handwired/pytest/basic/keymaps/default_json/keymap.json', 'json2c', '-')
    181     check_returncode(result)
    182     assert result.stdout == """#include QMK_KEYBOARD_H
    183 #if __has_include("keymap.h")
    184 #    include "keymap.h"
    185 #endif
    186 
    187 
    188 /* THIS FILE WAS GENERATED!
    189  *
    190  * This file was generated by qmk json2c. You may or may not want to
    191  * edit it directly.
    192  */
    193 
    194 const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    195     [0] = LAYOUT_ortho_1x1(KC_A)
    196 };
    197 
    198 
    199 
    200 
    201 #ifdef OTHER_KEYMAP_C
    202 #    include OTHER_KEYMAP_C
    203 #endif // OTHER_KEYMAP_C
    204 
    205 
    206 """
    207 
    208 
    209 def test_json2c_no_json():
    210     result = check_subcommand('json2c', 'keyboards/handwired/pytest/basic/keymaps/default/keymap.c')
    211     check_returncode(result, [1])
    212     assert 'Invalid JSON encountered' in result.stdout
    213 
    214 
    215 def test_info():
    216     result = check_subcommand('info', '-kb', 'handwired/pytest/basic')
    217     check_returncode(result)
    218     assert 'Keyboard Name: pytest' in result.stdout
    219     assert 'Processor: atmega32u4' in result.stdout
    220     assert 'Layout:' not in result.stdout
    221     assert 'k0' not in result.stdout
    222 
    223 
    224 def test_info_keyboard_render():
    225     result = check_subcommand('info', '-kb', 'handwired/pytest/basic', '-l')
    226     check_returncode(result)
    227     assert 'Keyboard Name: pytest' in result.stdout
    228     assert 'Processor: atmega32u4' in result.stdout
    229     assert 'Layouts:' in result.stdout
    230 
    231     if is_windows:
    232         assert '|  |' in result.stdout
    233     else:
    234         assert '│  │' in result.stdout
    235 
    236 
    237 def test_info_keymap_render():
    238     result = check_subcommand('info', '-kb', 'handwired/pytest/basic', '-km', 'default_json')
    239     check_returncode(result)
    240     assert 'Keyboard Name: pytest' in result.stdout
    241     assert 'Processor: atmega32u4' in result.stdout
    242 
    243     if is_windows:
    244         assert '|A |' in result.stdout
    245     else:
    246         assert '│A │' in result.stdout
    247 
    248 
    249 def test_info_matrix_render():
    250     result = check_subcommand('info', '-kb', 'handwired/pytest/basic', '-m')
    251     check_returncode(result)
    252     assert 'Keyboard Name: pytest' in result.stdout
    253     assert 'Processor: atmega32u4' in result.stdout
    254     assert 'LAYOUT_ortho_1x1' in result.stdout
    255 
    256     if is_windows:
    257         assert '|0A|' in result.stdout
    258     else:
    259         assert '│0A│' in result.stdout
    260 
    261     assert 'Matrix for "LAYOUT_ortho_1x1"' in result.stdout
    262 
    263 
    264 def test_c2json():
    265     result = check_subcommand("c2json", "-kb", "handwired/pytest/basic", "-km", "default", "keyboards/handwired/pytest/basic/keymaps/default/keymap.c")
    266     check_returncode(result)
    267     assert result.stdout.strip() == '{"keyboard": "handwired/pytest/basic", "keymap": "default", "layout": "LAYOUT_ortho_1x1", "layers": [["KC_A"]]}'
    268 
    269 
    270 def test_c2json_stdin():
    271     result = check_subcommand_stdin("keyboards/handwired/pytest/basic/keymaps/default/keymap.c", "c2json", "-kb", "handwired/pytest/basic", "-km", "default", "-")
    272     check_returncode(result)
    273     assert result.stdout.strip() == '{"keyboard": "handwired/pytest/basic", "keymap": "default", "layout": "LAYOUT_ortho_1x1", "layers": [["KC_A"]]}'
    274 
    275 
    276 def test_clean():
    277     result = check_subcommand('clean', '-a')
    278     check_returncode(result)
    279     assert (result.stdout.count('done') == 2 and 'userspace' not in result.stdout) or (result.stdout.count('done') == 3 and 'userspace' in result.stdout)
    280 
    281 
    282 def test_generate_api():
    283     result = check_subcommand('generate-api', '--dry-run', '--filter', 'handwired/pytest')
    284     check_returncode(result)
    285 
    286 
    287 def test_generate_rgb_breathe_table():
    288     result = check_subcommand("generate-rgb-breathe-table", "-c", "1.2", "-m", "127")
    289     check_returncode(result)
    290     assert 'Breathing center: 1.2' in result.stdout
    291     assert 'Breathing max:    127' in result.stdout
    292 
    293 
    294 def test_generate_config_h():
    295     result = check_subcommand('generate-config-h', '-kb', 'handwired/pytest/basic')
    296     check_returncode(result)
    297     assert '#    define DEVICE_VER 0x0001' in result.stdout
    298     assert '#    define DIODE_DIRECTION COL2ROW' in result.stdout
    299     assert '#    define MANUFACTURER "none"' in result.stdout
    300     assert '#    define PRODUCT "pytest"' in result.stdout
    301     assert '#    define PRODUCT_ID 0x6465' in result.stdout
    302     assert '#    define VENDOR_ID 0xFEED' in result.stdout
    303     assert '#    define MATRIX_COLS 1' in result.stdout
    304     assert '#    define MATRIX_COL_PINS { F4 }' in result.stdout
    305     assert '#    define MATRIX_ROWS 1' in result.stdout
    306     assert '#    define MATRIX_ROW_PINS { F5 }' in result.stdout
    307 
    308 
    309 def test_generate_rules_mk():
    310     result = check_subcommand('generate-rules-mk', '-kb', 'handwired/pytest/basic')
    311     check_returncode(result)
    312     assert 'BOOTLOADER ?= atmel-dfu' in result.stdout
    313     assert 'MCU ?= atmega32u4' in result.stdout
    314 
    315 
    316 def test_generate_version_h():
    317     result = check_subcommand('generate-version-h')
    318     check_returncode(result)
    319     assert '#define QMK_VERSION' in result.stdout
    320 
    321 
    322 def test_format_json_keyboard():
    323     result = check_subcommand('format-json', '--format', 'keyboard', 'lib/python/qmk/tests/minimal_info.json')
    324     check_returncode(result)
    325     assert result.stdout == '{\n    "keyboard_name": "tester",\n    "maintainer": "qmk",\n    "layouts": {\n        "LAYOUT": {\n            "layout": [\n                {"label": "KC_A", "matrix": [0, 0], "x": 0, "y": 0}\n            ]\n        }\n    }\n}\n'
    326 
    327 
    328 def test_format_json_keymap():
    329     result = check_subcommand('format-json', '--format', 'keymap', 'lib/python/qmk/tests/minimal_keymap.json')
    330     check_returncode(result)
    331     assert result.stdout == '{\n    "version": 1,\n    "keyboard": "handwired/pytest/basic",\n    "keymap": "test",\n    "layout": "LAYOUT_ortho_1x1",\n    "layers": [\n                [\n                        "KC_A"\n                ]\n    ]\n}\n'
    332 
    333 
    334 def test_format_json_keyboard_auto():
    335     result = check_subcommand('format-json', '--format', 'auto', 'lib/python/qmk/tests/minimal_info.json')
    336     check_returncode(result)
    337     assert result.stdout == '{\n    "keyboard_name": "tester",\n    "maintainer": "qmk",\n    "layouts": {\n        "LAYOUT": {\n            "layout": [\n                {"label": "KC_A", "matrix": [0, 0], "x": 0, "y": 0}\n            ]\n        }\n    }\n}\n'
    338 
    339 
    340 def test_format_json_keymap_auto():
    341     result = check_subcommand('format-json', '--format', 'auto', 'lib/python/qmk/tests/minimal_keymap.json')
    342     check_returncode(result)
    343     assert result.stdout == '{\n    "keyboard": "handwired/pytest/basic",\n    "keymap": "test",\n    "layers": [\n        ["KC_A"]\n    ],\n    "layout": "LAYOUT_ortho_1x1",\n    "version": 1\n}\n'
    344 
    345 
    346 def test_find_exists():
    347     result = check_subcommand('find', '-f', 'exists(rgb_matrix.split_count)', '-p', 'rgb_matrix.split_count')
    348     check_returncode(result)
    349     values = [s for s in result.stdout.splitlines() if 'rgb_matrix.split_count=' in s]
    350     assert len(values) > 0
    351     for s in values:
    352         assert '=None' not in s
    353         assert '=[' in s
    354 
    355 
    356 def test_find_absent():
    357     result = check_subcommand('find', '-f', 'absent(rgb_matrix.split_count)', '-p', 'rgb_matrix.split_count')
    358     check_returncode(result)
    359     values = [s for s in result.stdout.splitlines() if 'rgb_matrix.split_count=' in s]
    360     assert len(values) > 0
    361     for s in values:
    362         assert '=None' in s
    363         assert '=[' not in s
    364 
    365 
    366 def test_find_length():
    367     result = check_subcommand('find', '-f', 'length(matrix_pins.cols, 6)', '-p', 'matrix_pins.cols')
    368     check_returncode(result)
    369     values = [s for s in result.stdout.splitlines() if 'matrix_pins.cols=' in s]
    370     assert len(values) > 0
    371     for s in values:
    372         assert s.count(',') == 5
    373 
    374 
    375 def test_find_contains():
    376     result = check_subcommand('find', '-f', 'contains(matrix_pins.cols, B1)', '-p', 'matrix_pins.cols')
    377     check_returncode(result)
    378     values = [s for s in result.stdout.splitlines() if 'matrix_pins.cols=' in s]
    379     assert len(values) > 0
    380     for s in values:
    381         assert "'B1'" in s
    382 
    383 
    384 def test_find_multiple_conditions():
    385     # this is intended to match at least 'crkbd/rev1'
    386     result = check_subcommand(
    387         'find', '-f', 'exists(rgb_matrix.split_count)', '-f', 'contains(matrix_pins.cols, B1)', '-f', 'length(matrix_pins.cols, 6)', '-f', 'absent(eeprom.driver)', '-f', 'ws2812.pin == D3', '-p', 'rgb_matrix.split_count', '-p', 'matrix_pins.cols', '-p',
    388         'eeprom.driver', '-p', 'ws2812.pin'
    389     )
    390     check_returncode(result)
    391     rgb_matrix_split_count_values = [s for s in result.stdout.splitlines() if 'rgb_matrix.split_count=' in s]
    392     assert len(rgb_matrix_split_count_values) > 0
    393     for s in rgb_matrix_split_count_values:
    394         assert '=None' not in s
    395         assert '=[' in s
    396     matrix_pins_cols_values = [s for s in result.stdout.splitlines() if 'matrix_pins.cols=' in s]
    397     assert len(matrix_pins_cols_values) > 0
    398     for s in matrix_pins_cols_values:
    399         assert s.count(',') == 5
    400         assert "'B1'" in s
    401     eeprom_driver_values = [s for s in result.stdout.splitlines() if 'eeprom.driver=' in s]
    402     assert len(eeprom_driver_values) > 0
    403     for s in eeprom_driver_values:
    404         assert '=None' in s
    405     ws2812_pin_values = [s for s in result.stdout.splitlines() if 'ws2812.pin=' in s]
    406     assert len(ws2812_pin_values) > 0
    407     for s in ws2812_pin_values:
    408         assert '=D3' in s