Class |
Line # |
Actions |
|||
---|---|---|---|---|---|
FeatureStoreTest | 36 | 498 | 20 |
1 | /* | |
2 | * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) | |
3 | * Copyright (C) $$Year-Rel$$ The Jalview Authors | |
4 | * | |
5 | * This file is part of Jalview. | |
6 | * | |
7 | * Jalview is free software: you can redistribute it and/or | |
8 | * modify it under the terms of the GNU General Public License | |
9 | * as published by the Free Software Foundation, either version 3 | |
10 | * of the License, or (at your option) any later version. | |
11 | * | |
12 | * Jalview is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty | |
14 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR | |
15 | * PURPOSE. See the GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with Jalview. If not, see <http://www.gnu.org/licenses/>. | |
19 | * The Jalview Authors are detailed in the 'AUTHORS' file. | |
20 | */ | |
21 | package jalview.datamodel.features; | |
22 | ||
23 | import static org.testng.Assert.assertEquals; | |
24 | import static org.testng.Assert.assertFalse; | |
25 | import static org.testng.Assert.assertSame; | |
26 | import static org.testng.Assert.assertTrue; | |
27 | ||
28 | import jalview.datamodel.SequenceFeature; | |
29 | ||
30 | import java.util.ArrayList; | |
31 | import java.util.List; | |
32 | import java.util.Set; | |
33 | ||
34 | import org.testng.annotations.Test; | |
35 | ||
36 | public class FeatureStoreTest | |
37 | { | |
38 | ||
39 | 1 | @Test(groups = "Functional") |
40 | public void testFindFeatures_nonNested() | |
41 | { | |
42 | 1 | FeatureStore fs = new FeatureStore(); |
43 | 1 | fs.addFeature(new SequenceFeature("", "", 10, 20, Float.NaN, null)); |
44 | // same range different description | |
45 | 1 | fs.addFeature(new SequenceFeature("", "desc", 10, 20, Float.NaN, null)); |
46 | 1 | fs.addFeature(new SequenceFeature("", "", 15, 25, Float.NaN, null)); |
47 | 1 | fs.addFeature(new SequenceFeature("", "", 20, 35, Float.NaN, null)); |
48 | ||
49 | 1 | List<SequenceFeature> overlaps = fs.findOverlappingFeatures(1, 9); |
50 | 1 | assertTrue(overlaps.isEmpty()); |
51 | ||
52 | 1 | overlaps = fs.findOverlappingFeatures(8, 10); |
53 | 1 | assertEquals(overlaps.size(), 2); |
54 | 1 | assertEquals(overlaps.get(0).getEnd(), 20); |
55 | 1 | assertEquals(overlaps.get(1).getEnd(), 20); |
56 | ||
57 | 1 | overlaps = fs.findOverlappingFeatures(12, 16); |
58 | 1 | assertEquals(overlaps.size(), 3); |
59 | 1 | assertEquals(overlaps.get(0).getEnd(), 20); |
60 | 1 | assertEquals(overlaps.get(1).getEnd(), 20); |
61 | 1 | assertEquals(overlaps.get(2).getEnd(), 25); |
62 | ||
63 | 1 | overlaps = fs.findOverlappingFeatures(33, 33); |
64 | 1 | assertEquals(overlaps.size(), 1); |
65 | 1 | assertEquals(overlaps.get(0).getEnd(), 35); |
66 | } | |
67 | ||
68 | 1 | @Test(groups = "Functional") |
69 | public void testFindFeatures_nested() | |
70 | { | |
71 | 1 | FeatureStore fs = new FeatureStore(); |
72 | 1 | SequenceFeature sf1 = addFeature(fs, 10, 50); |
73 | 1 | SequenceFeature sf2 = addFeature(fs, 10, 40); |
74 | 1 | SequenceFeature sf3 = addFeature(fs, 20, 30); |
75 | // fudge feature at same location but different group (so is added) | |
76 | 1 | SequenceFeature sf4 = new SequenceFeature("", "", 20, 30, Float.NaN, |
77 | "different group"); | |
78 | 1 | fs.addFeature(sf4); |
79 | 1 | SequenceFeature sf5 = addFeature(fs, 35, 36); |
80 | ||
81 | 1 | List<SequenceFeature> overlaps = fs.findOverlappingFeatures(1, 9); |
82 | 1 | assertTrue(overlaps.isEmpty()); |
83 | ||
84 | 1 | overlaps = fs.findOverlappingFeatures(10, 15); |
85 | 1 | assertEquals(overlaps.size(), 2); |
86 | 1 | assertTrue(overlaps.contains(sf1)); |
87 | 1 | assertTrue(overlaps.contains(sf2)); |
88 | ||
89 | 1 | overlaps = fs.findOverlappingFeatures(45, 60); |
90 | 1 | assertEquals(overlaps.size(), 1); |
91 | 1 | assertTrue(overlaps.contains(sf1)); |
92 | ||
93 | 1 | overlaps = fs.findOverlappingFeatures(32, 38); |
94 | 1 | assertEquals(overlaps.size(), 3); |
95 | 1 | assertTrue(overlaps.contains(sf1)); |
96 | 1 | assertTrue(overlaps.contains(sf2)); |
97 | 1 | assertTrue(overlaps.contains(sf5)); |
98 | ||
99 | 1 | overlaps = fs.findOverlappingFeatures(15, 25); |
100 | 1 | assertEquals(overlaps.size(), 4); |
101 | 1 | assertTrue(overlaps.contains(sf1)); |
102 | 1 | assertTrue(overlaps.contains(sf2)); |
103 | 1 | assertTrue(overlaps.contains(sf3)); |
104 | 1 | assertTrue(overlaps.contains(sf4)); |
105 | } | |
106 | ||
107 | 1 | @Test(groups = "Functional") |
108 | public void testFindFeatures_mixed() | |
109 | { | |
110 | 1 | FeatureStore fs = new FeatureStore(); |
111 | 1 | SequenceFeature sf1 = addFeature(fs, 10, 50); |
112 | 1 | SequenceFeature sf2 = addFeature(fs, 1, 15); |
113 | 1 | SequenceFeature sf3 = addFeature(fs, 20, 30); |
114 | 1 | SequenceFeature sf4 = addFeature(fs, 40, 100); |
115 | 1 | SequenceFeature sf5 = addFeature(fs, 60, 100); |
116 | 1 | SequenceFeature sf6 = addFeature(fs, 70, 70); |
117 | ||
118 | 1 | List<SequenceFeature> overlaps = fs.findOverlappingFeatures(200, 200); |
119 | 1 | assertTrue(overlaps.isEmpty()); |
120 | ||
121 | 1 | overlaps = fs.findOverlappingFeatures(1, 9); |
122 | 1 | assertEquals(overlaps.size(), 1); |
123 | 1 | assertTrue(overlaps.contains(sf2)); |
124 | ||
125 | 1 | overlaps = fs.findOverlappingFeatures(5, 18); |
126 | 1 | assertEquals(overlaps.size(), 2); |
127 | 1 | assertTrue(overlaps.contains(sf1)); |
128 | 1 | assertTrue(overlaps.contains(sf2)); |
129 | ||
130 | 1 | overlaps = fs.findOverlappingFeatures(30, 40); |
131 | 1 | assertEquals(overlaps.size(), 3); |
132 | 1 | assertTrue(overlaps.contains(sf1)); |
133 | 1 | assertTrue(overlaps.contains(sf3)); |
134 | 1 | assertTrue(overlaps.contains(sf4)); |
135 | ||
136 | 1 | overlaps = fs.findOverlappingFeatures(80, 90); |
137 | 1 | assertEquals(overlaps.size(), 2); |
138 | 1 | assertTrue(overlaps.contains(sf4)); |
139 | 1 | assertTrue(overlaps.contains(sf5)); |
140 | ||
141 | 1 | overlaps = fs.findOverlappingFeatures(68, 70); |
142 | 1 | assertEquals(overlaps.size(), 3); |
143 | 1 | assertTrue(overlaps.contains(sf4)); |
144 | 1 | assertTrue(overlaps.contains(sf5)); |
145 | 1 | assertTrue(overlaps.contains(sf6)); |
146 | } | |
147 | ||
148 | /** | |
149 | * Helper method to add a feature of no particular type | |
150 | * | |
151 | * @param fs | |
152 | * @param from | |
153 | * @param to | |
154 | * @return | |
155 | */ | |
156 | 23 | SequenceFeature addFeature(FeatureStore fs, int from, int to) |
157 | { | |
158 | 23 | SequenceFeature sf1 = new SequenceFeature("", "", from, to, Float.NaN, |
159 | null); | |
160 | 23 | fs.addFeature(sf1); |
161 | 23 | return sf1; |
162 | } | |
163 | ||
164 | 1 | @Test(groups = "Functional") |
165 | public void testFindFeatures_contactFeatures() | |
166 | { | |
167 | 1 | FeatureStore fs = new FeatureStore(); |
168 | ||
169 | 1 | SequenceFeature sf = new SequenceFeature("disulphide bond", "bond", 10, |
170 | 20, Float.NaN, null); | |
171 | 1 | fs.addFeature(sf); |
172 | ||
173 | /* | |
174 | * neither contact point in range | |
175 | */ | |
176 | 1 | List<SequenceFeature> overlaps = fs.findOverlappingFeatures(1, 9); |
177 | 1 | assertTrue(overlaps.isEmpty()); |
178 | ||
179 | /* | |
180 | * neither contact point in range | |
181 | */ | |
182 | 1 | overlaps = fs.findOverlappingFeatures(11, 19); |
183 | 1 | assertTrue(overlaps.isEmpty()); |
184 | ||
185 | /* | |
186 | * first contact point in range | |
187 | */ | |
188 | 1 | overlaps = fs.findOverlappingFeatures(5, 15); |
189 | 1 | assertEquals(overlaps.size(), 1); |
190 | 1 | assertTrue(overlaps.contains(sf)); |
191 | ||
192 | /* | |
193 | * second contact point in range | |
194 | */ | |
195 | 1 | overlaps = fs.findOverlappingFeatures(15, 25); |
196 | 1 | assertEquals(overlaps.size(), 1); |
197 | 1 | assertTrue(overlaps.contains(sf)); |
198 | ||
199 | /* | |
200 | * both contact points in range | |
201 | */ | |
202 | 1 | overlaps = fs.findOverlappingFeatures(5, 25); |
203 | 1 | assertEquals(overlaps.size(), 1); |
204 | 1 | assertTrue(overlaps.contains(sf)); |
205 | } | |
206 | ||
207 | 1 | @Test(groups = "Functional") |
208 | public void testGetPositionalFeatures() | |
209 | { | |
210 | 1 | FeatureStore store = new FeatureStore(); |
211 | 1 | SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20, |
212 | Float.NaN, null); | |
213 | 1 | store.addFeature(sf1); |
214 | // same range, different description | |
215 | 1 | SequenceFeature sf2 = new SequenceFeature("Metal", "desc2", 10, 20, |
216 | Float.NaN, null); | |
217 | 1 | store.addFeature(sf2); |
218 | // discontiguous range | |
219 | 1 | SequenceFeature sf3 = new SequenceFeature("Metal", "desc", 30, 40, |
220 | Float.NaN, null); | |
221 | 1 | store.addFeature(sf3); |
222 | // overlapping range | |
223 | 1 | SequenceFeature sf4 = new SequenceFeature("Metal", "desc", 15, 35, |
224 | Float.NaN, null); | |
225 | 1 | store.addFeature(sf4); |
226 | // enclosing range | |
227 | 1 | SequenceFeature sf5 = new SequenceFeature("Metal", "desc", 5, 50, |
228 | Float.NaN, null); | |
229 | 1 | store.addFeature(sf5); |
230 | // non-positional feature | |
231 | 1 | SequenceFeature sf6 = new SequenceFeature("Metal", "desc", 0, 0, |
232 | Float.NaN, null); | |
233 | 1 | store.addFeature(sf6); |
234 | // contact feature | |
235 | 1 | SequenceFeature sf7 = new SequenceFeature("Disulphide bond", "desc", 18, |
236 | 45, Float.NaN, null); | |
237 | 1 | store.addFeature(sf7); |
238 | ||
239 | 1 | List<SequenceFeature> features = store.getPositionalFeatures(); |
240 | 1 | assertEquals(features.size(), 6); |
241 | 1 | assertTrue(features.contains(sf1)); |
242 | 1 | assertTrue(features.contains(sf2)); |
243 | 1 | assertTrue(features.contains(sf3)); |
244 | 1 | assertTrue(features.contains(sf4)); |
245 | 1 | assertTrue(features.contains(sf5)); |
246 | 1 | assertFalse(features.contains(sf6)); |
247 | 1 | assertTrue(features.contains(sf7)); |
248 | ||
249 | 1 | features = store.getNonPositionalFeatures(); |
250 | 1 | assertEquals(features.size(), 1); |
251 | 1 | assertTrue(features.contains(sf6)); |
252 | } | |
253 | ||
254 | 1 | @Test(groups = "Functional") |
255 | public void testDelete() | |
256 | { | |
257 | 1 | FeatureStore store = new FeatureStore(); |
258 | 1 | SequenceFeature sf1 = addFeature(store, 10, 20); |
259 | 1 | assertTrue(store.getPositionalFeatures().contains(sf1)); |
260 | ||
261 | /* | |
262 | * simple deletion | |
263 | */ | |
264 | 1 | assertTrue(store.delete(sf1)); |
265 | 1 | assertTrue(store.getPositionalFeatures().isEmpty()); |
266 | ||
267 | /* | |
268 | * non-positional feature deletion | |
269 | */ | |
270 | 1 | SequenceFeature sf2 = addFeature(store, 0, 0); |
271 | 1 | assertFalse(store.getPositionalFeatures().contains(sf2)); |
272 | 1 | assertTrue(store.getNonPositionalFeatures().contains(sf2)); |
273 | 1 | assertTrue(store.delete(sf2)); |
274 | 1 | assertTrue(store.getNonPositionalFeatures().isEmpty()); |
275 | ||
276 | /* | |
277 | * contact feature deletion | |
278 | */ | |
279 | 1 | SequenceFeature sf3 = new SequenceFeature("", "Disulphide Bond", 11, 23, |
280 | Float.NaN, null); | |
281 | 1 | store.addFeature(sf3); |
282 | 1 | assertEquals(store.getPositionalFeatures().size(), 1); |
283 | 1 | assertTrue(store.getPositionalFeatures().contains(sf3)); |
284 | 1 | assertTrue(store.delete(sf3)); |
285 | 1 | assertTrue(store.getPositionalFeatures().isEmpty()); |
286 | ||
287 | /* | |
288 | * nested feature deletion | |
289 | */ | |
290 | 1 | SequenceFeature sf4 = addFeature(store, 20, 30); |
291 | 1 | SequenceFeature sf5 = addFeature(store, 22, 26); // to NCList |
292 | 1 | SequenceFeature sf6 = addFeature(store, 23, 24); // child of sf5 |
293 | 1 | SequenceFeature sf7 = addFeature(store, 25, 25); // sibling of sf6 |
294 | 1 | SequenceFeature sf8 = addFeature(store, 24, 24); // child of sf6 |
295 | 1 | SequenceFeature sf9 = addFeature(store, 23, 23); // child of sf6 |
296 | 1 | assertEquals(store.getPositionalFeatures().size(), 6); |
297 | ||
298 | // delete a node with children - they take its place | |
299 | 1 | assertTrue(store.delete(sf6)); // sf8, sf9 should become children of sf5 |
300 | 1 | assertEquals(store.getPositionalFeatures().size(), 5); |
301 | 1 | assertFalse(store.getPositionalFeatures().contains(sf6)); |
302 | ||
303 | // delete a node with no children | |
304 | 1 | assertTrue(store.delete(sf7)); |
305 | 1 | assertEquals(store.getPositionalFeatures().size(), 4); |
306 | 1 | assertFalse(store.getPositionalFeatures().contains(sf7)); |
307 | ||
308 | // delete root of NCList | |
309 | 1 | assertTrue(store.delete(sf5)); |
310 | 1 | assertEquals(store.getPositionalFeatures().size(), 3); |
311 | 1 | assertFalse(store.getPositionalFeatures().contains(sf5)); |
312 | ||
313 | // continue the killing fields | |
314 | 1 | assertTrue(store.delete(sf4)); |
315 | 1 | assertEquals(store.getPositionalFeatures().size(), 2); |
316 | 1 | assertFalse(store.getPositionalFeatures().contains(sf4)); |
317 | ||
318 | 1 | assertTrue(store.delete(sf9)); |
319 | 1 | assertEquals(store.getPositionalFeatures().size(), 1); |
320 | 1 | assertFalse(store.getPositionalFeatures().contains(sf9)); |
321 | ||
322 | 1 | assertTrue(store.delete(sf8)); |
323 | 1 | assertTrue(store.getPositionalFeatures().isEmpty()); |
324 | } | |
325 | ||
326 | 1 | @Test(groups = "Functional") |
327 | public void testAddFeature() | |
328 | { | |
329 | 1 | FeatureStore fs = new FeatureStore(); |
330 | ||
331 | 1 | SequenceFeature sf1 = new SequenceFeature("Cath", "", 10, 20, Float.NaN, |
332 | null); | |
333 | 1 | SequenceFeature sf2 = new SequenceFeature("Cath", "", 10, 20, Float.NaN, |
334 | null); | |
335 | ||
336 | 1 | assertTrue(fs.addFeature(sf1)); |
337 | 1 | assertEquals(fs.getFeatureCount(true), 1); // positional |
338 | 1 | assertEquals(fs.getFeatureCount(false), 0); // non-positional |
339 | ||
340 | /* | |
341 | * re-adding the same or an identical feature should fail | |
342 | */ | |
343 | 1 | assertFalse(fs.addFeature(sf1)); |
344 | 1 | assertEquals(fs.getFeatureCount(true), 1); |
345 | 1 | assertFalse(fs.addFeature(sf2)); |
346 | 1 | assertEquals(fs.getFeatureCount(true), 1); |
347 | ||
348 | /* | |
349 | * add non-positional | |
350 | */ | |
351 | 1 | SequenceFeature sf3 = new SequenceFeature("Cath", "", 0, 0, Float.NaN, |
352 | null); | |
353 | 1 | assertTrue(fs.addFeature(sf3)); |
354 | 1 | assertEquals(fs.getFeatureCount(true), 1); // positional |
355 | 1 | assertEquals(fs.getFeatureCount(false), 1); // non-positional |
356 | 1 | SequenceFeature sf4 = new SequenceFeature("Cath", "", 0, 0, Float.NaN, |
357 | null); | |
358 | 1 | assertFalse(fs.addFeature(sf4)); // already stored |
359 | 1 | assertEquals(fs.getFeatureCount(true), 1); // positional |
360 | 1 | assertEquals(fs.getFeatureCount(false), 1); // non-positional |
361 | ||
362 | /* | |
363 | * add contact | |
364 | */ | |
365 | 1 | SequenceFeature sf5 = new SequenceFeature("Disulfide bond", "", 10, 20, |
366 | Float.NaN, null); | |
367 | 1 | assertTrue(fs.addFeature(sf5)); |
368 | 1 | assertEquals(fs.getFeatureCount(true), 2); // positional - add 1 for contact |
369 | 1 | assertEquals(fs.getFeatureCount(false), 1); // non-positional |
370 | 1 | SequenceFeature sf6 = new SequenceFeature("Disulfide bond", "", 10, 20, |
371 | Float.NaN, null); | |
372 | 1 | assertFalse(fs.addFeature(sf6)); // already stored |
373 | 1 | assertEquals(fs.getFeatureCount(true), 2); // no change |
374 | 1 | assertEquals(fs.getFeatureCount(false), 1); // no change |
375 | } | |
376 | ||
377 | 1 | @Test(groups = "Functional") |
378 | public void testIsEmpty() | |
379 | { | |
380 | 1 | FeatureStore fs = new FeatureStore(); |
381 | 1 | assertTrue(fs.isEmpty()); |
382 | 1 | assertEquals(fs.getFeatureCount(true), 0); |
383 | ||
384 | /* | |
385 | * non-nested feature | |
386 | */ | |
387 | 1 | SequenceFeature sf1 = new SequenceFeature("Cath", "", 10, 20, Float.NaN, |
388 | null); | |
389 | 1 | fs.addFeature(sf1); |
390 | 1 | assertFalse(fs.isEmpty()); |
391 | 1 | assertEquals(fs.getFeatureCount(true), 1); |
392 | 1 | fs.delete(sf1); |
393 | 1 | assertTrue(fs.isEmpty()); |
394 | 1 | assertEquals(fs.getFeatureCount(true), 0); |
395 | ||
396 | /* | |
397 | * non-positional feature | |
398 | */ | |
399 | 1 | sf1 = new SequenceFeature("Cath", "", 0, 0, Float.NaN, null); |
400 | 1 | fs.addFeature(sf1); |
401 | 1 | assertFalse(fs.isEmpty()); |
402 | 1 | assertEquals(fs.getFeatureCount(false), 1); // non-positional |
403 | 1 | assertEquals(fs.getFeatureCount(true), 0); // positional |
404 | 1 | fs.delete(sf1); |
405 | 1 | assertTrue(fs.isEmpty()); |
406 | 1 | assertEquals(fs.getFeatureCount(false), 0); |
407 | ||
408 | /* | |
409 | * contact feature | |
410 | */ | |
411 | 1 | sf1 = new SequenceFeature("Disulfide bond", "", 19, 49, Float.NaN, |
412 | null); | |
413 | 1 | fs.addFeature(sf1); |
414 | 1 | assertFalse(fs.isEmpty()); |
415 | 1 | assertEquals(fs.getFeatureCount(true), 1); |
416 | 1 | fs.delete(sf1); |
417 | 1 | assertTrue(fs.isEmpty()); |
418 | 1 | assertEquals(fs.getFeatureCount(true), 0); |
419 | ||
420 | /* | |
421 | * sf2, sf3 added as nested features | |
422 | */ | |
423 | 1 | sf1 = new SequenceFeature("Cath", "", 19, 49, Float.NaN, null); |
424 | 1 | SequenceFeature sf2 = new SequenceFeature("Cath", "", 20, 40, Float.NaN, |
425 | null); | |
426 | 1 | SequenceFeature sf3 = new SequenceFeature("Cath", "", 25, 35, Float.NaN, |
427 | null); | |
428 | 1 | fs.addFeature(sf1); |
429 | 1 | fs.addFeature(sf2); |
430 | 1 | fs.addFeature(sf3); |
431 | 1 | assertEquals(fs.getFeatureCount(true), 3); |
432 | 1 | assertTrue(fs.delete(sf1)); |
433 | 1 | assertEquals(fs.getFeatureCount(true), 2); |
434 | 1 | assertEquals(fs.features.size(), 2); |
435 | 1 | assertFalse(fs.isEmpty()); |
436 | 1 | assertTrue(fs.delete(sf2)); |
437 | 1 | assertEquals(fs.getFeatureCount(true), 1); |
438 | 1 | assertFalse(fs.isEmpty()); |
439 | 1 | assertTrue(fs.delete(sf3)); |
440 | 1 | assertEquals(fs.getFeatureCount(true), 0); |
441 | 1 | assertTrue(fs.isEmpty()); // all gone |
442 | } | |
443 | ||
444 | 1 | @Test(groups = "Functional") |
445 | public void testGetFeatureGroups() | |
446 | { | |
447 | 1 | FeatureStore fs = new FeatureStore(); |
448 | 1 | assertTrue(fs.getFeatureGroups(true).isEmpty()); |
449 | 1 | assertTrue(fs.getFeatureGroups(false).isEmpty()); |
450 | ||
451 | 1 | SequenceFeature sf1 = new SequenceFeature("Cath", "desc", 10, 20, 1f, |
452 | "group1"); | |
453 | 1 | fs.addFeature(sf1); |
454 | 1 | Set<String> groups = fs.getFeatureGroups(true); |
455 | 1 | assertEquals(groups.size(), 1); |
456 | 1 | assertTrue(groups.contains("group1")); |
457 | ||
458 | /* | |
459 | * add another feature of the same group, delete one, delete both | |
460 | */ | |
461 | 1 | SequenceFeature sf2 = new SequenceFeature("Cath", "desc", 20, 30, 1f, |
462 | "group1"); | |
463 | 1 | fs.addFeature(sf2); |
464 | 1 | groups = fs.getFeatureGroups(true); |
465 | 1 | assertEquals(groups.size(), 1); |
466 | 1 | assertTrue(groups.contains("group1")); |
467 | 1 | fs.delete(sf2); |
468 | 1 | groups = fs.getFeatureGroups(true); |
469 | 1 | assertEquals(groups.size(), 1); |
470 | 1 | assertTrue(groups.contains("group1")); |
471 | 1 | fs.delete(sf1); |
472 | 1 | groups = fs.getFeatureGroups(true); |
473 | 1 | assertTrue(fs.getFeatureGroups(true).isEmpty()); |
474 | ||
475 | 1 | SequenceFeature sf3 = new SequenceFeature("Cath", "desc", 20, 30, 1f, |
476 | "group2"); | |
477 | 1 | fs.addFeature(sf3); |
478 | 1 | SequenceFeature sf4 = new SequenceFeature("Cath", "desc", 20, 30, 1f, |
479 | "Group2"); | |
480 | 1 | fs.addFeature(sf4); |
481 | 1 | SequenceFeature sf5 = new SequenceFeature("Cath", "desc", 20, 30, 1f, |
482 | null); | |
483 | 1 | fs.addFeature(sf5); |
484 | 1 | groups = fs.getFeatureGroups(true); |
485 | 1 | assertEquals(groups.size(), 3); |
486 | 1 | assertTrue(groups.contains("group2")); |
487 | 1 | assertTrue(groups.contains("Group2")); // case sensitive |
488 | 1 | assertTrue(groups.contains(null)); // null allowed |
489 | 1 | assertTrue(fs.getFeatureGroups(false).isEmpty()); // non-positional |
490 | ||
491 | 1 | fs.delete(sf3); |
492 | 1 | groups = fs.getFeatureGroups(true); |
493 | 1 | assertEquals(groups.size(), 2); |
494 | 1 | assertFalse(groups.contains("group2")); |
495 | 1 | fs.delete(sf4); |
496 | 1 | groups = fs.getFeatureGroups(true); |
497 | 1 | assertEquals(groups.size(), 1); |
498 | 1 | assertFalse(groups.contains("Group2")); |
499 | 1 | fs.delete(sf5); |
500 | 1 | groups = fs.getFeatureGroups(true); |
501 | 1 | assertTrue(groups.isEmpty()); |
502 | ||
503 | /* | |
504 | * add non-positional feature | |
505 | */ | |
506 | 1 | SequenceFeature sf6 = new SequenceFeature("Cath", "desc", 0, 0, 1f, |
507 | "CathGroup"); | |
508 | 1 | fs.addFeature(sf6); |
509 | 1 | groups = fs.getFeatureGroups(false); |
510 | 1 | assertEquals(groups.size(), 1); |
511 | 1 | assertTrue(groups.contains("CathGroup")); |
512 | 1 | assertTrue(fs.delete(sf6)); |
513 | 1 | assertTrue(fs.getFeatureGroups(false).isEmpty()); |
514 | } | |
515 | ||
516 | 1 | @Test(groups = "Functional") |
517 | public void testGetTotalFeatureLength() | |
518 | { | |
519 | 1 | FeatureStore fs = new FeatureStore(); |
520 | 1 | assertEquals(fs.getTotalFeatureLength(), 0); |
521 | ||
522 | 1 | addFeature(fs, 10, 20); // 11 |
523 | 1 | assertEquals(fs.getTotalFeatureLength(), 11); |
524 | 1 | addFeature(fs, 17, 37); // 21 |
525 | 1 | SequenceFeature sf1 = addFeature(fs, 14, 74); // 61 |
526 | 1 | assertEquals(fs.getTotalFeatureLength(), 93); |
527 | ||
528 | // non-positional features don't count | |
529 | 1 | SequenceFeature sf2 = new SequenceFeature("Cath", "desc", 0, 0, 1f, |
530 | "group1"); | |
531 | 1 | fs.addFeature(sf2); |
532 | 1 | assertEquals(fs.getTotalFeatureLength(), 93); |
533 | ||
534 | // contact features count 1 | |
535 | 1 | SequenceFeature sf3 = new SequenceFeature("disulphide bond", "desc", 15, |
536 | 35, 1f, "group1"); | |
537 | 1 | fs.addFeature(sf3); |
538 | 1 | assertEquals(fs.getTotalFeatureLength(), 94); |
539 | ||
540 | 1 | assertTrue(fs.delete(sf1)); |
541 | 1 | assertEquals(fs.getTotalFeatureLength(), 33); |
542 | 1 | assertFalse(fs.delete(sf1)); |
543 | 1 | assertEquals(fs.getTotalFeatureLength(), 33); |
544 | 1 | assertTrue(fs.delete(sf2)); |
545 | 1 | assertEquals(fs.getTotalFeatureLength(), 33); |
546 | 1 | assertTrue(fs.delete(sf3)); |
547 | 1 | assertEquals(fs.getTotalFeatureLength(), 32); |
548 | } | |
549 | ||
550 | 1 | @Test(groups = "Functional") |
551 | public void testGetFeatureLength() | |
552 | { | |
553 | /* | |
554 | * positional feature | |
555 | */ | |
556 | 1 | SequenceFeature sf1 = new SequenceFeature("Cath", "desc", 10, 20, 1f, |
557 | "group1"); | |
558 | 1 | assertEquals(FeatureStore.getFeatureLength(sf1), 11); |
559 | ||
560 | /* | |
561 | * non-positional feature | |
562 | */ | |
563 | 1 | SequenceFeature sf2 = new SequenceFeature("Cath", "desc", 0, 0, 1f, |
564 | "CathGroup"); | |
565 | 1 | assertEquals(FeatureStore.getFeatureLength(sf2), 0); |
566 | ||
567 | /* | |
568 | * contact feature counts 1 | |
569 | */ | |
570 | 1 | SequenceFeature sf3 = new SequenceFeature("Disulphide Bond", "desc", 14, |
571 | 28, 1f, "AGroup"); | |
572 | 1 | assertEquals(FeatureStore.getFeatureLength(sf3), 1); |
573 | } | |
574 | ||
575 | 1 | @Test(groups = "Functional") |
576 | public void testMin() | |
577 | { | |
578 | 1 | assertEquals(FeatureStore.min(Float.NaN, Float.NaN), Float.NaN); |
579 | 1 | assertEquals(FeatureStore.min(Float.NaN, 2f), 2f); |
580 | 1 | assertEquals(FeatureStore.min(-2f, Float.NaN), -2f); |
581 | 1 | assertEquals(FeatureStore.min(2f, -3f), -3f); |
582 | } | |
583 | ||
584 | 1 | @Test(groups = "Functional") |
585 | public void testMax() | |
586 | { | |
587 | 1 | assertEquals(FeatureStore.max(Float.NaN, Float.NaN), Float.NaN); |
588 | 1 | assertEquals(FeatureStore.max(Float.NaN, 2f), 2f); |
589 | 1 | assertEquals(FeatureStore.max(-2f, Float.NaN), -2f); |
590 | 1 | assertEquals(FeatureStore.max(2f, -3f), 2f); |
591 | } | |
592 | ||
593 | 1 | @Test(groups = "Functional") |
594 | public void testGetMinimumScore_getMaximumScore() | |
595 | { | |
596 | 1 | FeatureStore fs = new FeatureStore(); |
597 | 1 | assertEquals(fs.getMinimumScore(true), Float.NaN); // positional |
598 | 1 | assertEquals(fs.getMaximumScore(true), Float.NaN); |
599 | 1 | assertEquals(fs.getMinimumScore(false), Float.NaN); // non-positional |
600 | 1 | assertEquals(fs.getMaximumScore(false), Float.NaN); |
601 | ||
602 | // add features with no score | |
603 | 1 | SequenceFeature sf1 = new SequenceFeature("type", "desc", 0, 0, |
604 | Float.NaN, "group"); | |
605 | 1 | fs.addFeature(sf1); |
606 | 1 | SequenceFeature sf2 = new SequenceFeature("type", "desc", 10, 20, |
607 | Float.NaN, "group"); | |
608 | 1 | fs.addFeature(sf2); |
609 | 1 | assertEquals(fs.getMinimumScore(true), Float.NaN); |
610 | 1 | assertEquals(fs.getMaximumScore(true), Float.NaN); |
611 | 1 | assertEquals(fs.getMinimumScore(false), Float.NaN); |
612 | 1 | assertEquals(fs.getMaximumScore(false), Float.NaN); |
613 | ||
614 | // add positional features with score | |
615 | 1 | SequenceFeature sf3 = new SequenceFeature("type", "desc", 10, 20, 1f, |
616 | "group"); | |
617 | 1 | fs.addFeature(sf3); |
618 | 1 | SequenceFeature sf4 = new SequenceFeature("type", "desc", 12, 16, 4f, |
619 | "group"); | |
620 | 1 | fs.addFeature(sf4); |
621 | 1 | assertEquals(fs.getMinimumScore(true), 1f); |
622 | 1 | assertEquals(fs.getMaximumScore(true), 4f); |
623 | 1 | assertEquals(fs.getMinimumScore(false), Float.NaN); |
624 | 1 | assertEquals(fs.getMaximumScore(false), Float.NaN); |
625 | ||
626 | // add non-positional features with score | |
627 | 1 | SequenceFeature sf5 = new SequenceFeature("type", "desc", 0, 0, 11f, |
628 | "group"); | |
629 | 1 | fs.addFeature(sf5); |
630 | 1 | SequenceFeature sf6 = new SequenceFeature("type", "desc", 0, 0, -7f, |
631 | "group"); | |
632 | 1 | fs.addFeature(sf6); |
633 | 1 | assertEquals(fs.getMinimumScore(true), 1f); |
634 | 1 | assertEquals(fs.getMaximumScore(true), 4f); |
635 | 1 | assertEquals(fs.getMinimumScore(false), -7f); |
636 | 1 | assertEquals(fs.getMaximumScore(false), 11f); |
637 | ||
638 | // delete one positional and one non-positional | |
639 | // min-max should be recomputed | |
640 | 1 | assertTrue(fs.delete(sf6)); |
641 | 1 | assertTrue(fs.delete(sf3)); |
642 | 1 | assertEquals(fs.getMinimumScore(true), 4f); |
643 | 1 | assertEquals(fs.getMaximumScore(true), 4f); |
644 | 1 | assertEquals(fs.getMinimumScore(false), 11f); |
645 | 1 | assertEquals(fs.getMaximumScore(false), 11f); |
646 | ||
647 | // delete remaining features with score | |
648 | 1 | assertTrue(fs.delete(sf4)); |
649 | 1 | assertTrue(fs.delete(sf5)); |
650 | 1 | assertEquals(fs.getMinimumScore(true), Float.NaN); |
651 | 1 | assertEquals(fs.getMaximumScore(true), Float.NaN); |
652 | 1 | assertEquals(fs.getMinimumScore(false), Float.NaN); |
653 | 1 | assertEquals(fs.getMaximumScore(false), Float.NaN); |
654 | ||
655 | // delete all features | |
656 | 1 | assertTrue(fs.delete(sf1)); |
657 | 1 | assertTrue(fs.delete(sf2)); |
658 | 1 | assertTrue(fs.isEmpty()); |
659 | 1 | assertEquals(fs.getMinimumScore(true), Float.NaN); |
660 | 1 | assertEquals(fs.getMaximumScore(true), Float.NaN); |
661 | 1 | assertEquals(fs.getMinimumScore(false), Float.NaN); |
662 | 1 | assertEquals(fs.getMaximumScore(false), Float.NaN); |
663 | } | |
664 | ||
665 | 1 | @Test(groups = "Functional") |
666 | public void testListContains() | |
667 | { | |
668 | 1 | assertFalse(FeatureStore.listContains(null, null)); |
669 | 1 | List<SequenceFeature> features = new ArrayList<>(); |
670 | 1 | assertFalse(FeatureStore.listContains(features, null)); |
671 | ||
672 | 1 | SequenceFeature sf1 = new SequenceFeature("type1", "desc1", 20, 30, 3f, |
673 | "group1"); | |
674 | 1 | assertFalse(FeatureStore.listContains(null, sf1)); |
675 | 1 | assertFalse(FeatureStore.listContains(features, sf1)); |
676 | ||
677 | 1 | features.add(sf1); |
678 | 1 | SequenceFeature sf2 = new SequenceFeature("type1", "desc1", 20, 30, 3f, |
679 | "group1"); | |
680 | 1 | SequenceFeature sf3 = new SequenceFeature("type1", "desc1", 20, 40, 3f, |
681 | "group1"); | |
682 | ||
683 | // sf2.equals(sf1) so contains should return true | |
684 | 1 | assertTrue(FeatureStore.listContains(features, sf2)); |
685 | 1 | assertFalse(FeatureStore.listContains(features, sf3)); |
686 | } | |
687 | ||
688 | 1 | @Test(groups = "Functional") |
689 | public void testGetFeaturesForGroup() | |
690 | { | |
691 | 1 | FeatureStore fs = new FeatureStore(); |
692 | ||
693 | /* | |
694 | * with no features | |
695 | */ | |
696 | 1 | assertTrue(fs.getFeaturesForGroup(true, null).isEmpty()); |
697 | 1 | assertTrue(fs.getFeaturesForGroup(false, null).isEmpty()); |
698 | 1 | assertTrue(fs.getFeaturesForGroup(true, "uniprot").isEmpty()); |
699 | 1 | assertTrue(fs.getFeaturesForGroup(false, "uniprot").isEmpty()); |
700 | ||
701 | /* | |
702 | * sf1: positional feature in the null group | |
703 | */ | |
704 | 1 | SequenceFeature sf1 = new SequenceFeature("Pfam", "desc", 4, 10, 0f, |
705 | null); | |
706 | 1 | fs.addFeature(sf1); |
707 | 1 | assertTrue(fs.getFeaturesForGroup(true, "uniprot").isEmpty()); |
708 | 1 | assertTrue(fs.getFeaturesForGroup(false, "uniprot").isEmpty()); |
709 | 1 | assertTrue(fs.getFeaturesForGroup(false, null).isEmpty()); |
710 | 1 | List<SequenceFeature> features = fs.getFeaturesForGroup(true, null); |
711 | 1 | assertEquals(features.size(), 1); |
712 | 1 | assertTrue(features.contains(sf1)); |
713 | ||
714 | /* | |
715 | * sf2: non-positional feature in the null group | |
716 | * sf3: positional feature in a non-null group | |
717 | * sf4: non-positional feature in a non-null group | |
718 | */ | |
719 | 1 | SequenceFeature sf2 = new SequenceFeature("Pfam", "desc", 0, 0, 0f, |
720 | null); | |
721 | 1 | SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 4, 10, 0f, |
722 | "Uniprot"); | |
723 | 1 | SequenceFeature sf4 = new SequenceFeature("Pfam", "desc", 0, 0, 0f, |
724 | "Rfam"); | |
725 | 1 | fs.addFeature(sf2); |
726 | 1 | fs.addFeature(sf3); |
727 | 1 | fs.addFeature(sf4); |
728 | ||
729 | 1 | features = fs.getFeaturesForGroup(true, null); |
730 | 1 | assertEquals(features.size(), 1); |
731 | 1 | assertTrue(features.contains(sf1)); |
732 | ||
733 | 1 | features = fs.getFeaturesForGroup(false, null); |
734 | 1 | assertEquals(features.size(), 1); |
735 | 1 | assertTrue(features.contains(sf2)); |
736 | ||
737 | 1 | features = fs.getFeaturesForGroup(true, "Uniprot"); |
738 | 1 | assertEquals(features.size(), 1); |
739 | 1 | assertTrue(features.contains(sf3)); |
740 | ||
741 | 1 | features = fs.getFeaturesForGroup(false, "Rfam"); |
742 | 1 | assertEquals(features.size(), 1); |
743 | 1 | assertTrue(features.contains(sf4)); |
744 | } | |
745 | ||
746 | 1 | @Test(groups = "Functional") |
747 | public void testShiftFeatures() | |
748 | { | |
749 | 1 | FeatureStore fs = new FeatureStore(); |
750 | 1 | assertFalse(fs.shiftFeatures(0, 1)); // nothing to do |
751 | ||
752 | 1 | SequenceFeature sf1 = new SequenceFeature("Cath", "", 2, 5, 0f, null); |
753 | 1 | fs.addFeature(sf1); |
754 | // nested feature: | |
755 | 1 | SequenceFeature sf2 = new SequenceFeature("Cath", "", 8, 14, 0f, null); |
756 | 1 | fs.addFeature(sf2); |
757 | // contact feature: | |
758 | 1 | SequenceFeature sf3 = new SequenceFeature("Disulfide bond", "", 23, 32, |
759 | 0f, null); | |
760 | 1 | fs.addFeature(sf3); |
761 | // non-positional feature: | |
762 | 1 | SequenceFeature sf4 = new SequenceFeature("Cath", "", 0, 0, 0f, null); |
763 | 1 | fs.addFeature(sf4); |
764 | ||
765 | /* | |
766 | * shift all features right by 5 | |
767 | */ | |
768 | 1 | assertTrue(fs.shiftFeatures(0, 5)); |
769 | ||
770 | // non-positional features untouched: | |
771 | 1 | List<SequenceFeature> nonPos = fs.getNonPositionalFeatures(); |
772 | 1 | assertEquals(nonPos.size(), 1); |
773 | 1 | assertTrue(nonPos.contains(sf4)); |
774 | ||
775 | // positional features are replaced | |
776 | 1 | List<SequenceFeature> pos = fs.getPositionalFeatures(); |
777 | 1 | assertEquals(pos.size(), 3); |
778 | 1 | assertFalse(pos.contains(sf1)); |
779 | 1 | assertFalse(pos.contains(sf2)); |
780 | 1 | assertFalse(pos.contains(sf3)); |
781 | 1 | SequenceFeatures.sortFeatures(pos, true); // ascending start pos |
782 | 1 | assertEquals(pos.get(0).getBegin(), 7); |
783 | 1 | assertEquals(pos.get(0).getEnd(), 10); |
784 | 1 | assertEquals(pos.get(1).getBegin(), 13); |
785 | 1 | assertEquals(pos.get(1).getEnd(), 19); |
786 | 1 | assertEquals(pos.get(2).getBegin(), 28); |
787 | 1 | assertEquals(pos.get(2).getEnd(), 37); |
788 | ||
789 | /* | |
790 | * now shift left by 15 | |
791 | * feature at [7-10] should be removed | |
792 | * feature at [13-19] should become [1-4] | |
793 | */ | |
794 | 1 | assertTrue(fs.shiftFeatures(0, -15)); |
795 | 1 | pos = fs.getPositionalFeatures(); |
796 | 1 | assertEquals(pos.size(), 2); |
797 | 1 | SequenceFeatures.sortFeatures(pos, true); |
798 | 1 | assertEquals(pos.get(0).getBegin(), 1); |
799 | 1 | assertEquals(pos.get(0).getEnd(), 4); |
800 | 1 | assertEquals(pos.get(1).getBegin(), 13); |
801 | 1 | assertEquals(pos.get(1).getEnd(), 22); |
802 | ||
803 | /* | |
804 | * shift right by 4 from position 2 onwards | |
805 | * feature at [1-4] unchanged, feature at [13-22] shifts | |
806 | */ | |
807 | 1 | assertTrue(fs.shiftFeatures(2, 4)); |
808 | 1 | pos = fs.getPositionalFeatures(); |
809 | 1 | assertEquals(pos.size(), 2); |
810 | 1 | SequenceFeatures.sortFeatures(pos, true); |
811 | 1 | assertEquals(pos.get(0).getBegin(), 1); |
812 | 1 | assertEquals(pos.get(0).getEnd(), 4); |
813 | 1 | assertEquals(pos.get(1).getBegin(), 17); |
814 | 1 | assertEquals(pos.get(1).getEnd(), 26); |
815 | ||
816 | /* | |
817 | * shift right by 4 from position 18 onwards | |
818 | * should be no change | |
819 | */ | |
820 | 1 | SequenceFeature f1 = pos.get(0); |
821 | 1 | SequenceFeature f2 = pos.get(1); |
822 | 1 | assertFalse(fs.shiftFeatures(18, 4)); // no update |
823 | 1 | pos = fs.getPositionalFeatures(); |
824 | 1 | assertEquals(pos.size(), 2); |
825 | 1 | SequenceFeatures.sortFeatures(pos, true); |
826 | 1 | assertSame(pos.get(0), f1); |
827 | 1 | assertSame(pos.get(1), f2); |
828 | } | |
829 | ||
830 | 1 | @Test(groups = "Functional") |
831 | public void testDelete_readd() | |
832 | { | |
833 | /* | |
834 | * add a feature and a nested feature | |
835 | */ | |
836 | 1 | FeatureStore store = new FeatureStore(); |
837 | 1 | SequenceFeature sf1 = addFeature(store, 10, 20); |
838 | // sf2 is nested in sf1 so will be stored in nestedFeatures | |
839 | 1 | SequenceFeature sf2 = addFeature(store, 12, 14); |
840 | 1 | List<SequenceFeature> features = store.getPositionalFeatures(); |
841 | 1 | assertEquals(features.size(), 2); |
842 | 1 | assertTrue(features.contains(sf1)); |
843 | 1 | assertTrue(features.contains(sf2)); |
844 | 1 | assertTrue(store.features.contains(sf1)); |
845 | 1 | assertTrue(store.features.contains(sf2)); |
846 | ||
847 | /* | |
848 | * delete the first feature | |
849 | */ | |
850 | 1 | assertTrue(store.delete(sf1)); |
851 | 1 | features = store.getPositionalFeatures(); |
852 | 1 | assertFalse(features.contains(sf1)); |
853 | 1 | assertTrue(features.contains(sf2)); |
854 | ||
855 | /* | |
856 | * re-add the 'nested' feature; is it now duplicated? | |
857 | */ | |
858 | 1 | store.addFeature(sf2); |
859 | 1 | features = store.getPositionalFeatures(); |
860 | 1 | assertEquals(features.size(), 1); |
861 | 1 | assertTrue(features.contains(sf2)); |
862 | } | |
863 | ||
864 | 1 | @Test(groups = "Functional") |
865 | public void testContains() | |
866 | { | |
867 | 1 | FeatureStore fs = new FeatureStore(); |
868 | 1 | SequenceFeature sf1 = new SequenceFeature("Cath", "", 10, 20, Float.NaN, |
869 | "group1"); | |
870 | 1 | SequenceFeature sf2 = new SequenceFeature("Cath", "", 10, 20, Float.NaN, |
871 | "group2"); | |
872 | 1 | SequenceFeature sf3 = new SequenceFeature("Cath", "", 0, 0, Float.NaN, |
873 | "group1"); | |
874 | 1 | SequenceFeature sf4 = new SequenceFeature("Cath", "", 0, 0, 0f, |
875 | "group1"); | |
876 | 1 | SequenceFeature sf5 = new SequenceFeature("Disulphide Bond", "", 5, 15, |
877 | Float.NaN, "group1"); | |
878 | 1 | SequenceFeature sf6 = new SequenceFeature("Disulphide Bond", "", 5, 15, |
879 | Float.NaN, "group2"); | |
880 | ||
881 | 1 | fs.addFeature(sf1); |
882 | 1 | fs.addFeature(sf3); |
883 | 1 | fs.addFeature(sf5); |
884 | 1 | assertTrue(fs.contains(sf1)); // positional feature |
885 | 1 | assertTrue(fs.contains(new SequenceFeature(sf1))); // identical feature |
886 | 1 | assertFalse(fs.contains(sf2)); // different group |
887 | 1 | assertTrue(fs.contains(sf3)); // non-positional |
888 | 1 | assertTrue(fs.contains(new SequenceFeature(sf3))); |
889 | 1 | assertFalse(fs.contains(sf4)); // different score |
890 | 1 | assertTrue(fs.contains(sf5)); // contact feature |
891 | 1 | assertTrue(fs.contains(new SequenceFeature(sf5))); |
892 | 1 | assertFalse(fs.contains(sf6)); // different group |
893 | ||
894 | /* | |
895 | * add a nested feature | |
896 | */ | |
897 | 1 | SequenceFeature sf7 = new SequenceFeature("Cath", "", 12, 16, Float.NaN, |
898 | "group1"); | |
899 | 1 | fs.addFeature(sf7); |
900 | 1 | assertTrue(fs.contains(sf7)); |
901 | 1 | assertTrue(fs.contains(new SequenceFeature(sf7))); |
902 | ||
903 | /* | |
904 | * delete the outer (enclosing, non-nested) feature | |
905 | */ | |
906 | 1 | fs.delete(sf1); |
907 | 1 | assertFalse(fs.contains(sf1)); |
908 | 1 | assertTrue(fs.contains(sf7)); |
909 | } | |
910 | } |