Class |
Line # |
Actions |
|||
---|---|---|---|---|---|
ChimeraCommandsTest | 40 | 148 | 26 |
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.ext.rbvi.chimera; | |
22 | ||
23 | import static org.testng.Assert.assertEquals; | |
24 | import static org.testng.Assert.assertTrue; | |
25 | ||
26 | import java.awt.Color; | |
27 | import java.util.HashMap; | |
28 | import java.util.LinkedHashMap; | |
29 | import java.util.List; | |
30 | import java.util.Map; | |
31 | ||
32 | import org.testng.annotations.BeforeClass; | |
33 | import org.testng.annotations.Test; | |
34 | ||
35 | import jalview.structure.AtomSpecModel; | |
36 | import jalview.structure.StructureCommand; | |
37 | import jalview.structure.StructureCommandI; | |
38 | import jalview.structure.StructureCommandsI.AtomSpecType; | |
39 | ||
40 | public class ChimeraCommandsTest | |
41 | { | |
42 | private ChimeraCommands testee; | |
43 | ||
44 | 1 | @BeforeClass(alwaysRun = true) |
45 | public void setUp() | |
46 | { | |
47 | 1 | testee = new ChimeraCommands(); |
48 | } | |
49 | ||
50 | 1 | @Test(groups = { "Functional" }) |
51 | public void testColourBySequence() | |
52 | { | |
53 | ||
54 | 1 | Map<Object, AtomSpecModel> map = new LinkedHashMap<>(); |
55 | 1 | ChimeraCommands.addAtomSpecRange(map, Color.blue, "0", 2, 5, "A"); |
56 | 1 | ChimeraCommands.addAtomSpecRange(map, Color.blue, "0", 7, 7, "B"); |
57 | 1 | ChimeraCommands.addAtomSpecRange(map, Color.blue, "0", 9, 23, "A"); |
58 | 1 | ChimeraCommands.addAtomSpecRange(map, Color.blue, "1", 1, 1, "A"); |
59 | 1 | ChimeraCommands.addAtomSpecRange(map, Color.blue, "1", 4, 7, "B"); |
60 | 1 | ChimeraCommands.addAtomSpecRange(map, Color.yellow, "1", 8, 8, "A"); |
61 | 1 | ChimeraCommands.addAtomSpecRange(map, Color.yellow, "1", 3, 5, "A"); |
62 | 1 | ChimeraCommands.addAtomSpecRange(map, Color.red, "0", 3, 5, "A"); |
63 | 1 | ChimeraCommands.addAtomSpecRange(map, Color.red, "0", 6, 9, "A"); |
64 | ||
65 | // Colours should appear in the Chimera command in the order in which | |
66 | // they were added; within colour, by model, by chain, ranges in start order | |
67 | 1 | List<StructureCommandI> commands = testee.colourBySequence(map); |
68 | 1 | assertEquals(commands.size(), 1); |
69 | 1 | assertEquals(commands.get(0).getCommand(), |
70 | "color #0000ff #0:2-5.A,9-23.A,7.B|#1:1.A,4-7.B;color #ffff00 #1:3-5.A,8.A;color #ff0000 #0:3-9.A"); | |
71 | } | |
72 | ||
73 | 1 | @Test(groups = { "Functional" }) |
74 | public void testSetAttributes() | |
75 | { | |
76 | /* | |
77 | * make a map of { featureType, {featureValue, {residue range specification } } } | |
78 | */ | |
79 | 1 | Map<String, Map<Object, AtomSpecModel>> featuresMap = new LinkedHashMap<>(); |
80 | 1 | Map<Object, AtomSpecModel> featureValues = new HashMap<>(); |
81 | ||
82 | /* | |
83 | * start with just one feature/value... | |
84 | */ | |
85 | 1 | featuresMap.put("chain", featureValues); |
86 | 1 | ChimeraCommands.addAtomSpecRange(featureValues, "X", "0", 8, 20, "A"); |
87 | ||
88 | 1 | List<StructureCommandI> commands = testee.setAttributes(featuresMap); |
89 | 1 | assertEquals(1, commands.size()); |
90 | ||
91 | /* | |
92 | * feature name gets a jv_ namespace prefix | |
93 | * feature value is quoted in case it contains spaces | |
94 | */ | |
95 | 1 | assertEquals(commands.get(0).getCommand(), |
96 | "setattr res jv_chain 'X' #0:8-20.A"); | |
97 | ||
98 | // add same feature value, overlapping range | |
99 | 1 | ChimeraCommands.addAtomSpecRange(featureValues, "X", "0", 3, 9, "A"); |
100 | // same feature value, contiguous range | |
101 | 1 | ChimeraCommands.addAtomSpecRange(featureValues, "X", "0", 21, 25, "A"); |
102 | 1 | commands = testee.setAttributes(featuresMap); |
103 | 1 | assertEquals(1, commands.size()); |
104 | 1 | assertEquals(commands.get(0).getCommand(), |
105 | "setattr res jv_chain 'X' #0:3-25.A"); | |
106 | ||
107 | // same feature value and model, different chain | |
108 | 1 | ChimeraCommands.addAtomSpecRange(featureValues, "X", "0", 21, 25, "B"); |
109 | // same feature value and chain, different model | |
110 | 1 | ChimeraCommands.addAtomSpecRange(featureValues, "X", "1", 26, 30, "A"); |
111 | 1 | commands = testee.setAttributes(featuresMap); |
112 | 1 | assertEquals(1, commands.size()); |
113 | 1 | String expected1 = "setattr res jv_chain 'X' #0:3-25.A,21-25.B|#1:26-30.A"; |
114 | 1 | assertEquals(commands.get(0).getCommand(), expected1); |
115 | ||
116 | // same feature, different value | |
117 | 1 | ChimeraCommands.addAtomSpecRange(featureValues, "Y", "0", 40, 50, "A"); |
118 | 1 | commands = testee.setAttributes(featuresMap); |
119 | 1 | assertEquals(2, commands.size()); |
120 | // commands are ordered by feature type but not by value | |
121 | // so test for the expected command in either order | |
122 | 1 | String cmd1 = commands.get(0).getCommand(); |
123 | 1 | String cmd2 = commands.get(1).getCommand(); |
124 | 1 | assertTrue(cmd1.equals(expected1) || cmd2.equals(expected1)); |
125 | 1 | String expected2 = "setattr res jv_chain 'Y' #0:40-50.A"; |
126 | 1 | assertTrue(cmd1.equals(expected2) || cmd2.equals(expected2)); |
127 | ||
128 | 1 | featuresMap.clear(); |
129 | 1 | featureValues.clear(); |
130 | 1 | featuresMap.put("side-chain binding!", featureValues); |
131 | 1 | ChimeraCommands.addAtomSpecRange(featureValues, |
132 | "<html>metal <a href=\"http:a.b.c/x\"> 'ion!", "0", 7, 15, "A"); | |
133 | // feature names are sanitised to change non-alphanumeric to underscore | |
134 | // feature values are sanitised to encode single quote characters | |
135 | 1 | commands = testee.setAttributes(featuresMap); |
136 | 1 | assertEquals(commands.size(), 1); |
137 | 1 | String expected3 = "setattr res jv_side_chain_binding_ '<html>metal <a href=\"http:a.b.c/x\"> 'ion!' #0:7-15.A"; |
138 | 1 | assertTrue(commands.get(0).getCommand().equals(expected3)); |
139 | } | |
140 | ||
141 | /** | |
142 | * Tests for the method that prefixes and sanitises a feature name so it can | |
143 | * be used as a valid, namespaced attribute name in Chimera or PyMol | |
144 | */ | |
145 | 1 | @Test(groups = { "Functional" }) |
146 | public void testMakeAttributeName() | |
147 | { | |
148 | 1 | assertEquals(testee.makeAttributeName(null), "jv_"); |
149 | 1 | assertEquals(testee.makeAttributeName(""), "jv_"); |
150 | 1 | assertEquals(testee.makeAttributeName("helix"), "jv_helix"); |
151 | 1 | assertEquals(testee.makeAttributeName("Hello World 24"), |
152 | "jv_Hello_World_24"); | |
153 | 1 | assertEquals(testee.makeAttributeName("!this is-a_very*{odd(name"), |
154 | "jv__this_is_a_very__odd_name"); | |
155 | // name ending in color gets underscore appended | |
156 | 1 | assertEquals(testee.makeAttributeName("helixColor"), "jv_helixColor_"); |
157 | } | |
158 | ||
159 | 1 | @Test(groups = "Functional") |
160 | public void testGetAtomSpec() | |
161 | { | |
162 | 1 | AtomSpecModel model = new AtomSpecModel(); |
163 | 1 | assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), ""); |
164 | 1 | model.addRange("1", 2, 4, "A"); |
165 | 1 | assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), |
166 | "#1:2-4.A"); | |
167 | 1 | model.addRange("1", 8, 8, "A"); |
168 | 1 | assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), |
169 | "#1:2-4.A,8.A"); | |
170 | 1 | model.addRange("1", 5, 7, "B"); |
171 | 1 | assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), |
172 | "#1:2-4.A,8.A,5-7.B"); | |
173 | 1 | model.addRange("1", 3, 5, "A"); |
174 | 1 | assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), |
175 | "#1:2-5.A,8.A,5-7.B"); | |
176 | 1 | model.addRange("0", 1, 4, "B"); |
177 | 1 | assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), |
178 | "#0:1-4.B|#1:2-5.A,8.A,5-7.B"); | |
179 | 1 | model.addRange("0", 5, 9, "C"); |
180 | 1 | assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), |
181 | "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-7.B"); | |
182 | 1 | model.addRange("1", 8, 10, "B"); |
183 | 1 | assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), |
184 | "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-10.B"); | |
185 | 1 | model.addRange("1", 8, 9, "B"); |
186 | 1 | assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), |
187 | "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-10.B"); | |
188 | 1 | model.addRange("0", 3, 10, "C"); // subsumes 5-9 |
189 | 1 | assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), |
190 | "#0:1-4.B,3-10.C|#1:2-5.A,8.A,5-10.B"); | |
191 | 1 | model.addRange("5", 25, 35, " "); |
192 | 1 | assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), |
193 | "#0:1-4.B,3-10.C|#1:2-5.A,8.A,5-10.B|#5:25-35."); | |
194 | ||
195 | } | |
196 | ||
197 | 1 | @Test(groups = { "Functional" }) |
198 | public void testSuperposeStructures() | |
199 | { | |
200 | 1 | AtomSpecModel ref = new AtomSpecModel(); |
201 | 1 | ref.addRange("1", 12, 14, "A"); |
202 | 1 | ref.addRange("1", 18, 18, "B"); |
203 | 1 | ref.addRange("1", 22, 23, "B"); |
204 | 1 | AtomSpecModel toAlign = new AtomSpecModel(); |
205 | 1 | toAlign.addRange("2", 15, 17, "B"); |
206 | 1 | toAlign.addRange("2", 20, 21, "B"); |
207 | 1 | toAlign.addRange("2", 22, 22, "C"); |
208 | 1 | List<StructureCommandI> command = testee.superposeStructures(ref, |
209 | toAlign, AtomSpecType.ALPHA); | |
210 | // qualifier to restrict match to CA and no altlocs | |
211 | 1 | String carbonAlphas = "@CA&~@.B-Z&~@.2-9"; |
212 | 1 | String refSpec = "#1:12-14.A,18.B,22-23.B"; |
213 | 1 | String toAlignSpec = "#2:15-17.B,20-21.B,22.C"; |
214 | 1 | String expected = String.format("match %s%s %s%s; ribbon %s|%s; focus", |
215 | toAlignSpec, carbonAlphas, refSpec, carbonAlphas, toAlignSpec, | |
216 | refSpec); | |
217 | 1 | assertEquals(command.get(0).getCommand(), expected); |
218 | } | |
219 | ||
220 | 1 | @Test(groups = "Functional") |
221 | public void testGetAtomSpec_alphaOnly() | |
222 | { | |
223 | 1 | AtomSpecModel model = new AtomSpecModel(); |
224 | 1 | assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA), ""); |
225 | 1 | model.addRange("1", 2, 4, "A"); |
226 | 1 | assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA), |
227 | "#1:2-4.A@CA&~@.B-Z&~@.2-9"); | |
228 | 1 | model.addRange("1", 8, 8, "A"); |
229 | 1 | assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA), |
230 | "#1:2-4.A,8.A@CA&~@.B-Z&~@.2-9"); | |
231 | 1 | model.addRange("1", 5, 7, "B"); |
232 | 1 | assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA), |
233 | "#1:2-4.A,8.A,5-7.B@CA&~@.B-Z&~@.2-9"); | |
234 | 1 | model.addRange("1", 3, 5, "A"); |
235 | 1 | assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA), |
236 | "#1:2-5.A,8.A,5-7.B@CA&~@.B-Z&~@.2-9"); | |
237 | 1 | model.addRange("0", 1, 4, "B"); |
238 | 1 | assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA), |
239 | "#0:1-4.B@CA&~@.B-Z&~@.2-9|#1:2-5.A,8.A,5-7.B@CA&~@.B-Z&~@.2-9"); | |
240 | 1 | model.addRange("0", 5, 9, "C"); |
241 | 1 | assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA), |
242 | "#0:1-4.B,5-9.C@CA&~@.B-Z&~@.2-9|#1:2-5.A,8.A,5-7.B@CA&~@.B-Z&~@.2-9"); | |
243 | 1 | model.addRange("1", 8, 10, "B"); |
244 | 1 | assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA), |
245 | "#0:1-4.B,5-9.C@CA&~@.B-Z&~@.2-9|#1:2-5.A,8.A,5-10.B@CA&~@.B-Z&~@.2-9"); | |
246 | 1 | model.addRange("1", 8, 9, "B"); |
247 | 1 | assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA), |
248 | "#0:1-4.B,5-9.C@CA&~@.B-Z&~@.2-9|#1:2-5.A,8.A,5-10.B@CA&~@.B-Z&~@.2-9"); | |
249 | 1 | model.addRange("0", 3, 10, "C"); // subsumes 5-9 |
250 | 1 | assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA), |
251 | "#0:1-4.B,3-10.C@CA&~@.B-Z&~@.2-9|#1:2-5.A,8.A,5-10.B@CA&~@.B-Z&~@.2-9"); | |
252 | 1 | model.addRange("5", 25, 35, " "); // empty chain code |
253 | 1 | assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA), |
254 | "#0:1-4.B,3-10.C@CA&~@.B-Z&~@.2-9|#1:2-5.A,8.A,5-10.B@CA&~@.B-Z&~@.2-9|#5:25-35.@CA&~@.B-Z&~@.2-9"); | |
255 | ||
256 | } | |
257 | ||
258 | 1 | @Test(groups = "Functional") |
259 | public void testGetModelStartNo() | |
260 | { | |
261 | 1 | assertEquals(testee.getModelStartNo(), 0); |
262 | } | |
263 | ||
264 | 1 | @Test(groups = "Functional") |
265 | public void testGetResidueSpec() | |
266 | { | |
267 | 1 | assertEquals(testee.getResidueSpec("ALA"), "::ALA"); |
268 | } | |
269 | ||
270 | 1 | @Test(groups = "Functional") |
271 | public void testShowBackbone() | |
272 | { | |
273 | 1 | List<StructureCommandI> cmds = testee.showBackbone(); |
274 | 1 | assertEquals(cmds.size(), 1); |
275 | 1 | assertEquals(cmds.get(0).getCommand(), |
276 | "~display all;~ribbon;chain @CA|P"); | |
277 | } | |
278 | ||
279 | 1 | @Test(groups = "Functional") |
280 | public void testOpenCommandFile() | |
281 | { | |
282 | 1 | assertEquals(testee.openCommandFile("nowhere").getCommand(), |
283 | "open cmd:nowhere"); | |
284 | } | |
285 | ||
286 | 1 | @Test(groups = "Functional") |
287 | public void testSaveSession() | |
288 | { | |
289 | 1 | assertEquals(testee.saveSession("somewhere").getCommand(), |
290 | "save somewhere"); | |
291 | } | |
292 | ||
293 | 1 | @Test(groups = "Functional") |
294 | public void testColourByChain() | |
295 | { | |
296 | 1 | assertEquals(testee.colourByChain().getCommand(), "rainbow chain"); |
297 | } | |
298 | ||
299 | 1 | @Test(groups = { "Functional" }) |
300 | public void testSetBackgroundColour() | |
301 | { | |
302 | 1 | StructureCommandI cmd = testee.setBackgroundColour(Color.PINK); |
303 | 1 | assertEquals(cmd.getCommand(), "set bgColor #ffafaf"); |
304 | } | |
305 | ||
306 | 1 | @Test(groups = { "Functional" }) |
307 | public void testLoadFile() | |
308 | { | |
309 | 1 | StructureCommandI cmd = testee.loadFile("/some/filepath"); |
310 | 1 | assertEquals(cmd.getCommand(), "open /some/filepath"); |
311 | } | |
312 | ||
313 | 1 | @Test(groups = { "Functional" }) |
314 | public void testOpenSession() | |
315 | { | |
316 | 1 | StructureCommandI cmd = testee.openSession("/some/filepath"); |
317 | 1 | assertEquals(cmd.getCommand(), "open chimera:/some/filepath"); |
318 | } | |
319 | ||
320 | 1 | @Test(groups = "Functional") |
321 | public void testColourByCharge() | |
322 | { | |
323 | 1 | List<StructureCommandI> cmds = testee.colourByCharge(); |
324 | 1 | assertEquals(cmds.size(), 1); |
325 | 1 | assertEquals(cmds.get(0).getCommand(), |
326 | "color white;color red ::ASP,GLU;color blue ::LYS,ARG;color yellow ::CYS"); | |
327 | } | |
328 | ||
329 | 1 | @Test(groups = "Functional") |
330 | public void testGetColourCommand() | |
331 | { | |
332 | 1 | assertEquals( |
333 | testee.colourResidues("something", Color.MAGENTA).getCommand(), | |
334 | "color #ff00ff something"); | |
335 | } | |
336 | ||
337 | 1 | @Test(groups = "Functional") |
338 | public void testFocusView() | |
339 | { | |
340 | 1 | assertEquals(testee.focusView().getCommand(), "focus"); |
341 | } | |
342 | ||
343 | 1 | @Test(groups = "Functional") |
344 | public void testSetAttribute() | |
345 | { | |
346 | 1 | AtomSpecModel model = new AtomSpecModel(); |
347 | 1 | model.addRange("1", 89, 92, "A"); |
348 | 1 | model.addRange("2", 12, 20, "B"); |
349 | 1 | model.addRange("2", 8, 9, "B"); |
350 | 1 | assertEquals(testee.setAttribute("jv_kd", "27.3", model).getCommand(), |
351 | "setattr res jv_kd '27.3' #1:89-92.A|#2:8-9.B,12-20.B"); | |
352 | } | |
353 | ||
354 | 1 | @Test(groups = "Functional") |
355 | public void testCloseViewer() | |
356 | { | |
357 | 1 | assertEquals(testee.closeViewer(), new StructureCommand("stop really")); |
358 | } | |
359 | ||
360 | 1 | @Test(groups = "Functional") |
361 | public void testGetSelectedResidues() | |
362 | { | |
363 | 1 | assertEquals(testee.getSelectedResidues(), |
364 | new StructureCommand("list selection level residue")); | |
365 | } | |
366 | ||
367 | 1 | @Test(groups = "Functional") |
368 | public void testListResidueAttributes() | |
369 | { | |
370 | 1 | assertEquals(testee.listResidueAttributes(), |
371 | new StructureCommand("list resattr")); | |
372 | } | |
373 | ||
374 | 1 | @Test(groups = "Functional") |
375 | public void testGetResidueAttributes() | |
376 | { | |
377 | 1 | assertEquals(testee.getResidueAttributes("binding site"), |
378 | new StructureCommand("list residues attr 'binding site'")); | |
379 | } | |
380 | ||
381 | 1 | @Test(groups = "Functional") |
382 | public void testStartNotifications() | |
383 | { | |
384 | 1 | List<StructureCommandI> cmds = testee.startNotifications("to here"); |
385 | 1 | assertEquals(cmds.size(), 2); |
386 | 1 | assertEquals(cmds.get(0), |
387 | new StructureCommand("listen start models url to here")); | |
388 | 1 | assertEquals(cmds.get(1), new StructureCommand( |
389 | "listen start select prefix SelectionChanged url to here")); | |
390 | } | |
391 | ||
392 | 1 | @Test(groups = "Functional") |
393 | public void testStopNotifications() | |
394 | { | |
395 | 1 | List<StructureCommandI> cmds = testee.stopNotifications(); |
396 | 1 | assertEquals(cmds.size(), 2); |
397 | 1 | assertEquals(cmds.get(0), new StructureCommand("listen stop models")); |
398 | 1 | assertEquals(cmds.get(1), |
399 | new StructureCommand("listen stop selection")); | |
400 | } | |
401 | } |