-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathrun_test_suite.py
540 lines (403 loc) · 15.8 KB
/
run_test_suite.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
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
#!/usr/bin/env python3
'''
This is a Python script with a suite of tests for the Quiver library.
This tests the accuracy of the Quiver library by ensuring that the
correct PDB lines are returned for a given tag. And that no PDB lines
are lost during manipulation of the Quiver file.
'''
import sys
import os
import math
import uuid
import pandas as pd
import glob
from quiver import Quiver
# Define a custom Exception class
class TestFailed(Exception):
pass
def test_zip_and_extract(basedir):
'''
Test that we can turn a directory of PDB files into a Quiver file and
then extract the PDB files from the Quiver file. And that the extracted
PDB files are identical to the original PDB files.
'''
# Go into the test directory
os.chdir(f'{basedir}/test')
# Create a temporary directory
os.system('mkdir -p zipextract')
os.chdir('zipextract')
# Zip the PDB files into a Quiver file
os.system(f'{basedir}/qvfrompdbs {basedir}/test/input_for_tests/*.pdb > test.qv')
# Extract the PDB files from the Quiver file
os.chdir(f'{basedir}/test/zipextract')
os.system(f'{basedir}/qvextract test.qv')
# Compare the extracted PDB files to the original PDB files
for file in glob.glob('*.pdb'):
otherfile = f'{basedir}/test/input_for_tests/{file}'
# Compare the two files
with open(file, 'r') as f:
lines = f.readlines()
with open(otherfile, 'r') as f:
otherlines = f.readlines()
if (lines != otherlines):
raise TestFailed(f'File {file} does not match {otherfile}')
# Remove the temporary directory
os.chdir(f'{basedir}')
os.system(f'rm -r {basedir}/test/zipextract')
def test_qvls(basedir):
'''
Test that qvls returns the correct list of tags for a given Quiver file
'''
# Go into the test directory
os.chdir(f'{basedir}/test')
# Create a temporary directory
os.system('mkdir -p do_qvls')
os.chdir('do_qvls')
# Zip the PDB files into a Quiver file
os.system(f'{basedir}/qvfrompdbs {basedir}/test/input_for_tests/*.pdb > test.qv')
# Run qvls
os.system(f'{basedir}/qvls test.qv > qvls_output.txt')
# Ensure that all pdbs are listed
with open('qvls_output.txt', 'r') as f:
lines = [line.strip() for line in f.readlines()]
# Get the list of PDB files
pdbs = glob.glob(f'{basedir}/test/input_for_tests/*.pdb')
# Check that all PDB files are listed
for pdb in pdbs:
tag = os.path.basename(pdb)[:-4]
if tag not in lines:
print(f'LINES: {lines}')
print(f'TAG: {tag}')
raise TestFailed(f'PDB file {tag} not listed in qvls output')
# Clean up
os.chdir(f'{basedir}')
os.system(f'rm -r {basedir}/test/do_qvls')
def test_qvextractspecific(basedir):
'''
Test that qvextractspecific returns the correct PDB lines for a given
set of tags in a Quiver file
'''
# Go into the test directory
os.chdir(f'{basedir}/test')
# Create a temporary directory
os.system('mkdir -p do_qvextractspecific')
os.chdir('do_qvextractspecific')
# Zip the PDB files into a Quiver file
os.system(f'{basedir}/qvfrompdbs {basedir}/test/input_for_tests/*.pdb > test.qv')
# Get 5 random tags
os.system(f'{basedir}/qvls test.qv | shuf | head -n 5 > tags.txt')
# Run qvextractspecific
os.system(f'cat tags.txt | {basedir}/qvextractspecific test.qv')
# Ensure that the correct PDB lines are returned
with open('tags.txt', 'r') as f:
lines = [line.strip() for line in f.readlines()]
# Get list of pdbs in this directory
pdbs = glob.glob('*.pdb')
pdb_tags = [os.path.basename(pdb)[:-4] for pdb in pdbs]
if (set(lines) != set(pdb_tags)):
print(f'lines: {lines}')
print(f'pdb_tags: {pdb_tags}')
raise TestFailed(f'qvextractspecific did not return the correct PDB files')
for tag in lines:
# Get the current PDB file
currpdb = f'{tag}.pdb'
with open(currpdb, 'r') as f:
currpdblines = [line.strip() for line in f.readlines()]
# Get the PDB file
pdb = f'{basedir}/test/input_for_tests/{tag}.pdb'
# Get the PDB lines
with open(pdb, 'r') as f:
pdblines = [line.strip() for line in f.readlines()]
# Check that the two files are identical
if (currpdblines != pdblines):
raise TestFailed(f'PDB file {currpdb} does not match {pdb}')
# Clean up
os.chdir(f'{basedir}')
os.system(f'rm -r {basedir}/test/do_qvextractspecific')
def test_qvslice(basedir):
'''
Test that qvslice returns the correct PDB lines for a given set of
tags in a Quiver file
We are testing the following:
1) qvslice is slicing the requested tags
2) qvslice is correctly zipping the requested tags, this is tested
by running qvextract on the output of qvslice and comparing the
extracted PDB files to the original PDB files
'''
# Go into the test directory
os.chdir(f'{basedir}/test')
# Create a temporary directory
os.system('mkdir -p do_qvslice')
os.chdir('do_qvslice')
# Zip the PDB files into a Quiver file
os.system(f'{basedir}/qvfrompdbs {basedir}/test/input_for_tests/*.pdb > test.qv')
# Get 5 random tags
os.system(f'{basedir}/qvls test.qv | shuf | head -n 5 > tags.txt')
# Run qvslice
os.system(f'cat tags.txt | {basedir}/qvslice test.qv > sliced.qv')
# Run qvextract
os.system(f'{basedir}/qvextract sliced.qv')
# Get the list of PDB files in this directory
pdbs = glob.glob('*.pdb')
pdb_tags = [os.path.basename(pdb)[:-4] for pdb in pdbs]
# Ensure that the correct PDB files are returned
with open('tags.txt', 'r') as f:
tags = [line.strip() for line in f.readlines()]
if (set(tags) != set(pdb_tags)):
print(f'PDB tags: {pdb_tags}')
print(f'Tags: {tags}')
raise TestFailed(f'qvslice did not return the correct PDB files')
for tag in tags:
# Get the current PDB file
currpdb = f'{tag}.pdb'
with open(currpdb, 'r') as f:
currpdblines = [line.strip() for line in f.readlines()]
# Get the PDB file
pdb = f'{basedir}/test/input_for_tests/{tag}.pdb'
# Get the PDB lines
with open(pdb, 'r') as f:
pdblines = [line.strip() for line in f.readlines()]
# Check that the two files are identical
if (currpdblines != pdblines):
raise TestFailed(f'PDB file {currpdb} does not match {pdb}')
# Clean up
os.chdir(f'{basedir}')
os.system(f'rm -r {basedir}/test/do_qvslice')
def test_qvsplit(basedir):
'''
Test that qvsplit returns the correct PDB lines for a given set of
tags in a Quiver file
We will test that:
1) qvsplit returns the correct number of quiver files
2) Each Quiver file contains the correct number of PDB files
3) All pdbs which were zipped into the original quiver file are represented
in the output quiver files
These three conditions are sufficient to ensure that qvsplit is working
'''
# Go into the test directory
os.chdir(f'{basedir}/test')
# Create a temporary directory
os.system('mkdir -p do_qvsplit')
os.chdir('do_qvsplit')
# Zip the PDB files into a Quiver file
os.system(f'{basedir}/qvfrompdbs {basedir}/test/input_for_tests/*.pdb > test.qv')
os.mkdir('split')
os.chdir('split')
# Run qvsplit
os.system(f'{basedir}/qvsplit ../test.qv 3')
# Get the number of pdb files in the original quiver file
num_pdbs = len(glob.glob(f'{basedir}/test/input_for_tests/*.pdb'))
# Get the number of quiver files in the split directory
num_quivers = len(glob.glob('*.qv'))
# Ensure that the correct number of quiver files were created
if num_quivers != math.ceil(num_pdbs / 3):
raise TestFailed(f'qvsplit did not return the correct number of quiver files, '\
f'expected {math.ceil(num_pdbs / 3)}, got {num_quivers}')
# Ensure that each quiver file contains the correct number of PDB files
# Except for the last quiver file, which may contain fewer PDB files
for i in range(num_quivers - 1):
# Get the number of PDB files in this quiver file
local_num_pdbs = 0
with open(f'split_{i}.qv', 'r') as f:
for line in f.readlines():
if line.startswith('QV_TAG'):
local_num_pdbs += 1
# Ensure that the correct number of PDB files were created
if local_num_pdbs != 3:
raise TestFailed(f'qvsplit did not return the correct number of PDB files, '\
f'expected 3, got {local_num_pdbs}')
# Reset local_num_pdbs
local_num_pdbs = 0
with open(f'split_{num_quivers - 1}.qv', 'r') as f:
for line in f.readlines():
if line.startswith('QV_TAG'):
local_num_pdbs += 1
# Ensure that the correct number of PDB files were created
if local_num_pdbs != num_pdbs % 3:
raise TestFailed(f'qvsplit did not return the correct number of PDB files, '\
f'expected {num_pdbs % 3}, got {local_num_pdbs}')
# Extract the PDB files from each quiver file
for i in range(num_quivers):
# Run qvextract
os.system(f'{basedir}/qvextract split_{i}.qv')
# Get the list of PDB files in this directory
pdbs = glob.glob('*.pdb')
pdb_tags = [os.path.basename(pdb)[:-4] for pdb in pdbs]
# Ensure that the correct PDB files are returned
tags = []
for i in glob.glob(f'{basedir}/test/input_for_tests/*.pdb'):
tags.append(os.path.basename(i)[:-4])
if (set(tags) != set(pdb_tags)):
print(f'PDB tags: {pdb_tags}')
print(f'Tags: {tags}')
raise TestFailed(f'qvsplit did not return the correct PDB files')
for tag in tags:
# Get the current PDB file
currpdb = f'{tag}.pdb'
with open(currpdb, 'r') as f:
currpdblines = [line.strip() for line in f.readlines()]
# Get the PDB file
pdb = f'{basedir}/test/input_for_tests/{tag}.pdb'
# Get the PDB lines
with open(pdb, 'r') as f:
pdblines = [line.strip() for line in f.readlines()]
# Check that the two files are identical
if (currpdblines != pdblines):
raise TestFailed(f'PDB file {currpdb} does not match {pdb}')
# Clean up
os.chdir(f'{basedir}')
os.system(f'rm -r {basedir}/test/do_qvsplit')
def test_qvrename(basedir):
'''
Test that qvrename correctly renames the entries of a Quiver file.
We are testing:
1) qvrename assigns the correct names to the Quiver file entries
2) The entries in the Quiver file are unchanged except for the names
3) Checks that the score lines are also renamed
'''
# Go into the test directory
os.chdir(f'{basedir}/test')
# Create a temporary directory
os.system('mkdir -p do_qvrename')
os.chdir('do_qvrename')
# Get the input Quiver filepath
qvpath = f'{basedir}/test/input_for_tests/designs_scored.qv'
os.mkdir('input_pdbs')
os.chdir('input_pdbs')
# Extract the PDB files from the Quiver file
os.system(f'{basedir}/qvextract {qvpath}')
# Store current path
inpdbdir = os.getcwd()
os.chdir(f'{basedir}/test/do_qvrename')
# Get the Quiver tags
inqv = Quiver(qvpath, 'r')
tags = inqv.get_tags()
# Make a random set of names to rename the entries to
newtags = [f'{uuid.uuid4()}' for tag in tags]
# Write the new tags to a file
with open('newtags.txt', 'w') as f:
for tag in newtags:
f.write(f'{tag}\n')
# Run qvrename
os.system(f'cat newtags.txt | {basedir}/qvrename {qvpath} > renamed.qv')
# Run qvextract
os.system(f'{basedir}/qvextract renamed.qv')
# Pair the old tags with the new tags and assert that the PDB files are the same
# other than the name
for idx in range(len(tags)):
# Get the new PDB file
currpdb = f'{newtags[idx]}.pdb'
with open(currpdb, 'r') as f:
currpdblines = [line.strip() for line in f.readlines()]
# Get the original PDB file
pdb = f'{inpdbdir}/{tags[idx]}.pdb'
# Get the PDB lines
with open(pdb, 'r') as f:
pdblines = [line.strip() for line in f.readlines()]
# Check that the two files are identical
if (currpdblines != pdblines):
raise TestFailed(f'PDB file {currpdb} does not match {pdb}')
# Now compare the score lines of the two Quiver files
# Get the score lines of the original Quiver file
os.system(f'{basedir}/qvscorefile {qvpath}')
ogsc = qvpath.split('.')[0] + '.sc'
ogdf = pd.read_csv(ogsc, sep='\t')
# Get the score lines of the new Quiver file
os.system(f'{basedir}/qvscorefile renamed.qv')
newsc = 'renamed.sc'
newdf = pd.read_csv(newsc, sep='\t')
# Pair the old tags with the new tags and assert that the score lines are the same
# other than the name
for idx in range(len(tags)):
# Get the old score line with 'tag' column equal to the old tag
oldrow = ogdf.loc[ogdf['tag'] == tags[idx]]
# Get the new score line with 'tag' column equal to the new tag
newrow = newdf.loc[newdf['tag'] == newtags[idx]]
# Check that the two rows are identical except for the tag
for key in oldrow.keys():
if (key == 'tag'):
continue
if (oldrow[key].values[0] != newrow[key].values[0]):
raise TestFailed(f'Score line {idx} does not match between old and new Quiver files')
# Clean up
os.chdir(f'{basedir}')
os.system(f'rm -r {basedir}/test/do_qvrename')
#### Main
###############################
# Run through all the tests, logging which ones fail
# Get the base directory
basedir = os.path.dirname(os.path.realpath(__file__))
passed = 0
total = 0
# Zip and Extract Test
print(f'Running zip and extract test')
try:
test_zip_and_extract(basedir)
print(f'Passed zip and extract test')
passed += 1
total += 1
except TestFailed as e:
print(f"Test with name test_zip_and_extract failed with error: {e}")
total += 1
print('\n')
# qvls Test
print(f'Running qvls test')
try:
test_qvls(basedir)
print(f'Passed qvls test')
passed += 1
total += 1
except TestFailed as e:
print(f"Test with name test_qvls failed with error: {e}")
total += 1
print('\n')
# qvextractspecific Test
print(f'Running qvextractspecific test')
try:
test_qvextractspecific(basedir)
print(f'Passed qvextractspecific test')
passed += 1
total += 1
except TestFailed as e:
print(f"Test with name test_qvextractspecific failed with error: {e}")
total += 1
print('\n')
# qvslice Test
print(f'Running qvslice test')
try:
test_qvslice(basedir)
print(f'Passed qvslice test')
passed += 1
total += 1
except TestFailed as e:
print(f"Test with name test_qvslice failed with error: {e}")
os.system(f'rm -r {basedir}/test/do_qvslice')
total += 1
print('\n')
# qvsplit Test
print(f'Running qvsplit test')
try:
test_qvsplit(basedir)
print(f'Passed qvsplit test')
passed += 1
total += 1
except TestFailed as e:
print(f"Test with name test_qvsplit failed with error: {e}")
os.system(f'rm -r {basedir}/test/do_qvsplit')
total += 1
print('\n')
# qvrename Test
print(f'Running qvrename test')
try :
test_qvrename(basedir)
print(f'Passed qvrename test')
passed += 1
total += 1
except TestFailed as e:
print(f"Test with name test_qvrename failed with error: {e}")
os.system(f'rm -r {basedir}/test/do_qvrename')
total += 1
print('\n')
print('#'*50)
print(f'Passed {passed}/{total} tests')
print('#'*50)