forked from qmk/qmk_compiler
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest_qmk_compiler.py
303 lines (245 loc) · 11.5 KB
/
test_qmk_compiler.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
"""Test suite for qmk_compiler.
This file tests most of the functionality in qmk_compiler. Given the nature
of qmk_compiler most of the functionality depends on qmk_firmware being
checked out and available. To satisfy this requirement
`test_0000_checkout_qmk_skip_cache()` must be tested first, and
`test_9999_teardown()` must be tested last. It would be better if this were
setup as a test fixture, and some day it will be. Setting up a proper test
fixture here is a non-trivial task and will take work that the author has
not had time to put in yet.
"""
import filecmp
import os
import os.path
import re
import shutil
from tempfile import mkstemp
import pytest
import update_kb_redis
import qmk_commands
############################################################################
# Setup Environment #
############################################################################
def test_0000_checkout_qmk_skip_cache():
"""Make sure that we successfully git clone qmk_firmware and generate the version.txt hash.
"""
qmk_commands.checkout_qmk(skip_cache=True)
assert os.path.exists('qmk_firmware/version.txt')
############################################################################
# Begin Tests #
############################################################################
# Source code retrieval testing. Make sure we're storing and fetching the
# correct source every way we can. At least test_0001 must be run before any
# other test in this file or they will all fail.
def test_0001_fetch_source_qmk():
"""Make sure that we can upload a qmk_firmware.zip and download it again.
"""
os.rename('qmk_firmware.zip', 'qmk_firmware_cloned.zip')
qmk_commands.fetch_source('qmk_firmware', uncompress=False)
assert filecmp.cmp('qmk_firmware_cloned.zip', 'qmk_firmware.zip')
os.remove('qmk_firmware_cloned.zip')
os.remove('qmk_firmware.zip')
def test_0002_checkout_qmk_cache():
"""Make sure that we fetch the cache from QMK and don't clone from git.
"""
git_hash = open('qmk_firmware/version.txt', 'r').read()
shutil.rmtree('qmk_firmware')
update_kb_redis.checkout_qmk(require_cache=True)
cached_hash = open('qmk_firmware/version.txt', 'r').read()
assert git_hash == cached_hash
def test_0003_checkout_qmk_skip_and_require_cache():
"""Make sure that we can't pass skip_cache and require_cache at the same time
"""
with pytest.raises(ValueError):
update_kb_redis.checkout_qmk(skip_cache=True, require_cache=True)
# Test out functions that require qmk_firmware be in place on disk.
def test_0010_keyboard_list():
"""Test qmk_commands.keyboard.list()
"""
keyboard_list = update_kb_redis.list_keyboards()
assert len(keyboard_list) > 0
for keyboard in keyboard_list:
assert os.path.exists(os.path.join('qmk_firmware', 'keyboards', keyboard))
def test_0011_find_firmware_file_hex():
"""Make sure that qmk_commands.find_firmware_file() can find a hex file.
"""
fd, test_firmware = mkstemp(suffix='.hex', dir='.')
firmware_file = qmk_commands.find_firmware_file()
os.remove(test_firmware)
assert os.path.split(test_firmware)[-1] == firmware_file
def test_0012_find_firmware_file_bin():
"""Make sure that qmk_commands.find_firmware_file() can find a bin file.
"""
fd, test_firmware = mkstemp(suffix='.bin', dir='.')
firmware_file = qmk_commands.find_firmware_file()
os.remove(test_firmware)
assert os.path.split(test_firmware)[-1] == firmware_file
def test_0013_git_hash():
"""Make sure that we get a valid hex string in the git hash.
"""
hash = qmk_commands.git_hash()
assert re.match(r'^[0-9a-f]+$', hash)
assert len(hash) == 40
def test_0017_find_all_layouts_cluecard():
"""Make sure that update_kb_redis.find_all_layouts() can find the cluecard layout.
"""
layouts = update_kb_redis.find_all_layouts('clueboard/card')
assert list(layouts) == ['LAYOUT']
assert layouts['LAYOUT'] == {
'key_count': 12,
'layout': [
{'label': 'k00', 'w': 1, 'x': 0, 'y': 0},
{'label': 'k01', 'w': 1, 'x': 1, 'y': 0},
{'label': 'k02', 'w': 1, 'x': 2, 'y': 0},
{'label': 'k10', 'w': 1, 'x': 0, 'y': 1},
{'label': 'k12', 'w': 1, 'x': 1, 'y': 1},
{'label': 'k20', 'w': 1, 'x': 0, 'y': 2},
{'label': 'k21', 'w': 1, 'x': 1, 'y': 2},
{'label': 'k22', 'w': 1, 'x': 2, 'y': 2},
{'label': 'k11', 'w': 1, 'x': 0, 'y': 3},
{'label': 'k30', 'w': 1, 'x': 0, 'y': 4},
{'label': 'k31', 'w': 1, 'x': 1, 'y': 4},
{'label': 'k32', 'w': 1, 'x': 2, 'y': 4},
]
} # yapf: disable
### FIXME(skullydazed/anyone): Need to write a test for update_kb_redis.parse_config_h()
def test_0019_parse_config_h_file_cluecard():
"""Make sure the config.h parsing works.
"""
config_h = update_kb_redis.parse_config_h_file('qmk_firmware/keyboards/clueboard/card/config.h')
assert config_h == {
'VENDOR_ID': '0xC1ED',
'PRODUCT_ID': '0x2330',
'DEVICE_VER': '0x0001',
'MANUFACTURER': 'Clueboard',
'PRODUCT': 'ATMEGA32U4 Firmware Dev Kit',
'DESCRIPTION': 'A small board to help you hack on QMK.',
'MATRIX_ROWS': '4',
'MATRIX_COLS': '3',
'MATRIX_ROW_PINS': '{ F0, F5, F4, B4 }',
'MATRIX_COL_PINS': '{ F1, F7, F6 }',
'UNUSED_PINS': True,
'DIODE_DIRECTION': 'ROW2COL',
'DEBOUNCE': '20',
'BACKLIGHT_LEVELS': '6',
'RGB_DI_PIN': 'E6',
'RGBLED_NUM': '4',
'RGBLIGHT_HUE_STEP': '10',
'RGBLIGHT_SAT_STEP': '17',
'RGBLIGHT_VAL_STEP': '17',
}
## FIXME(skullydazed/anyone): Write a test for update_kb_redis.parse_rules_mk
def test_0021_parse_rules_mk_file_cluecard():
"""Make sure the rules.mk parsing works.
"""
rules_mk = update_kb_redis.parse_rules_mk_file('qmk_firmware/keyboards/clueboard/card/rules.mk')
assert rules_mk == {
'AUDIO_ENABLE': 'yes',
'BACKLIGHT_DRIVER': 'custom',
'BACKLIGHT_ENABLE': 'yes',
'BLUETOOTH_ENABLE': 'no',
'BOOTLOADER': 'atmel-dfu',
'BOOTMAGIC_ENABLE': 'no',
'COMMAND_ENABLE': 'yes',
'CONSOLE_ENABLE': 'yes',
'EXTRAKEY_ENABLE': 'yes',
'LINK_TIME_OPTIMIZATION_ENABLE': 'yes',
'MCU': 'atmega32u4',
'MIDI_ENABLE': 'no',
'MOUSEKEY_ENABLE': 'yes',
'NKRO_ENABLE': 'no',
'RGBLIGHT_ENABLE': 'yes',
'UNICODE_ENABLE': 'no',
}
def test_0022_default_key():
"""Test update_kb_redis.default_key().
"""
new_key1 = update_kb_redis.default_key()
new_key2 = update_kb_redis.default_key()
assert new_key1 == {'x': 3, 'y': 4, 'w': 1}
assert new_key2 == {'x': 4, 'y': 4, 'w': 1}
def test_0022_default_key_label():
"""Test update_kb_redis.default_key('label').
"""
new_key1 = update_kb_redis.default_key('label')
new_key2 = update_kb_redis.default_key('label')
assert new_key1 == {'label': 'label', 'x': 5, 'y': 4, 'w': 1}
assert new_key2 == {'label': 'label', 'x': 6, 'y': 4, 'w': 1}
def test_0023_preprocess_source_cluecard():
"""Test the clang preprocessor function.
"""
keymap_text = update_kb_redis.preprocess_source('qmk_firmware/keyboards/clueboard/card/keymaps/default/keymap.c')
assert 'constuint16_tPROGMEMkeymaps' in keymap_text
assert 'RGB_TOG,RGB_SAI,RGB_VAI,RGB_HUD,RGB_HUI,RGB_MOD,RGB_SAD,RGB_VAD,BL_STEP' in keymap_text
def test_0024_populate_enums_planck():
"""Test the enum extraction code.
"""
keymap_file = 'qmk_firmware/keyboards/planck/keymaps/default/keymap.c'
keymap_text = update_kb_redis.preprocess_source(keymap_file)
keymap = update_kb_redis.extract_layouts(keymap_text, keymap_file)
keymap_enums = update_kb_redis.populate_enums(keymap_text, keymap)
assert '[0]=LAYOUT_planck_grid' in keymap_enums
assert '[1]=LAYOUT_planck_grid' in keymap_enums
assert '[2]=LAYOUT_planck_grid' in keymap_enums
assert '[3]=LAYOUT_planck_grid' in keymap_enums
assert '[4]=LAYOUT_planck_grid' in keymap_enums
assert '[5]=LAYOUT_planck_grid' in keymap_enums
assert '[6]=LAYOUT_planck_grid' in keymap_enums
def test_0025_extract_layouts_cluecard():
"""Test our layout extraction code.
"""
keymap_file = 'qmk_firmware/keyboards/clueboard/card/keymaps/default/keymap.c'
keymap_text = update_kb_redis.preprocess_source(keymap_file)
layouts = update_kb_redis.extract_layouts(keymap_text, keymap_file)
assert layouts == 'constuint16_tPROGMEMkeymaps[][MATRIX_ROWS][MATRIX_COLS]={[0]=LAYOUT(RGB_TOG,RGB_SAI,RGB_VAI,RGB_HUD,RGB_HUI,RGB_MOD,RGB_SAD,RGB_VAD,BL_STEP,SONG_SU,SONG_SC,SONG_GB)}'
def test_0026_extract_keymap_cluecard():
"""Test our keymap extraction code.
"""
keymap_file = 'qmk_firmware/keyboards/clueboard/card/keymaps/default/keymap.c'
layout_macro, layer_list = update_kb_redis.extract_keymap(keymap_file)
assert layout_macro == 'LAYOUT'
assert layer_list == [['RGB_TOG', 'RGB_SAI', 'RGB_VAI', 'RGB_HUD', 'RGB_HUI', 'RGB_MOD', 'RGB_SAD', 'RGB_VAD', 'BL_STEP', 'SONG_SU', 'SONG_SC', 'SONG_GB']]
def test_0027_find_layouts_cluecard():
"""Test our layout detection code.
"""
keymap_file = 'qmk_firmware/keyboards/clueboard/card/card.h'
layouts = update_kb_redis.find_layouts(keymap_file)
assert layouts == {
'LAYOUT': {
'key_count': 12,
'layout': [
{'x': 0, 'y': 0, 'w': 1, 'label': 'k00'}, {'x': 1, 'y': 0, 'w': 1, 'label': 'k01'},
{'x': 2, 'y': 0, 'w': 1, 'label': 'k02'}, {'x': 0, 'y': 1, 'w': 1, 'label': 'k10'},
{'x': 1, 'y': 1, 'w': 1, 'label': 'k12'}, {'x': 0, 'y': 2, 'w': 1, 'label': 'k20'},
{'x': 1, 'y': 2, 'w': 1, 'label': 'k21'}, {'x': 2, 'y': 2, 'w': 1, 'label': 'k22'},
{'x': 0, 'y': 3, 'w': 1, 'label': 'k11'}, {'x': 0, 'y': 4, 'w': 1, 'label': 'k30'},
{'x': 1, 'y': 4, 'w': 1, 'label': 'k31'}, {'x': 2, 'y': 4, 'w': 1, 'label': 'k32'}
]
}
} # yapf: disable
def test_0028_find_info_json_clueboard_66_rev3():
"""Make sure we can detect all the info.json files for cluecard.
"""
info_json_files = update_kb_redis.find_info_json('clueboard/66/rev3')
assert info_json_files == ['qmk_firmware/keyboards/clueboard/66/rev3/../../info.json', 'qmk_firmware/keyboards/clueboard/66/rev3/../info.json']
def test_0030_merge_info_json_cluecard():
"""Test our code for merging an info.json into the existing keyboard info.
"""
keyboard_info = {
'keyboard_name': 'clueboard/card',
'keyboard_folder': 'clueboard/card',
'maintainer': 'qmk',
}
merged_keyboard_info = update_kb_redis.merge_info_json('qmk_firmware/keyboards/clueboard/info.json', keyboard_info)
assert merged_keyboard_info == {'keyboard_name': 'clueboard/card', 'keyboard_folder': 'clueboard/card', 'maintainer': 'skullydazed', 'manufacturer': 'Clueboard'}
def test_0031_find_readme_cluecard():
"""Make sure we can find a readme.md file.
"""
readme = update_kb_redis.find_readme('qmk_firmware/keyboards/clueboard/card')
assert readme == 'qmk_firmware/keyboards/clueboard/card/readme.md'
############################################################################
# Clean Up Environment #
############################################################################
def test_9999_teardown():
shutil.rmtree('qmk_firmware')
assert not os.path.exists('qmk_firmware')