1   /*
2    * Copyright 2006-2010 Sam Adams <sea36 at users.sourceforge.net>
3    *
4    * This file is part of JNI-InChI.
5    *
6    * JNI-InChI is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU Lesser General Public License as published
8    * by the Free Software Foundation, either version 3 of the License, or
9    * (at your option) any later version.
10   *
11   * JNI-InChI is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU Lesser General Public License for more details.
15   *
16   * You should have received a copy of the GNU Lesser General Public License
17   * along with JNI-InChI.  If not, see <http://www.gnu.org/licenses/>.
18   */
19  package net.sf.jniinchi;
20  
21  import org.junit.Assert;
22  import org.junit.Ignore;
23  import org.junit.Test;
24  
25  import java.util.ArrayList;
26  import java.util.List;
27  import java.util.Random;
28  
29  import static org.junit.Assert.*;
30  
31  public class TestJniInchiWrapper {
32  
33      // Test molecules
34  
35      /**
36       * Generates input for a chlorine atom.
37       *
38       * @param options
39       * @return
40       * @throws JniInchiException
41       */
42      private static JniInchiInput getChlorineAtom(final String options)
43              throws JniInchiException {
44          JniInchiInput input = new JniInchiInput(options);
45  
46          // Generate atoms
47          input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000, "Cl"));
48          input.getAtom(0).setImplicitH(0);
49          return input;
50      }
51  
52      /**
53       * Generates input for a chlorine atom.
54       *
55       * @param options
56       * @return
57       * @throws JniInchiException
58       */
59      private static JniInchiInput getChlorineIon(final String options)
60              throws JniInchiException {
61          JniInchiInput input = new JniInchiInput(options);
62  
63          // Generate atoms
64          JniInchiAtom a1 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
65                  "Cl"));
66          a1.setCharge(-1);
67          input.getAtom(0).setRadical(INCHI_RADICAL.SINGLET);
68  
69          return input;
70      }
71  
72      /**
73       * Generates input for hydrogen chloride, with implicit H atom.
74       *
75       * @param options
76       * @return
77       * @throws JniInchiException
78       */
79      private static JniInchiInput getHydrogenChlorideImplicitH(
80              final String options) throws JniInchiException {
81          JniInchiInput input = new JniInchiInput(options);
82  
83          // Generate atoms
84          JniInchiAtom a1 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
85                  "Cl"));
86          a1.setImplicitH(1);
87  
88          return input;
89      }
90  
91      /**
92       * Generates input for hydrogen chloride, with implicit protium atom.
93       *
94       * @param options
95       * @return
96       * @throws JniInchiException
97       */
98      private static JniInchiInput getHydrogenChlorideImplicitP(
99              final String options) throws JniInchiException {
100         JniInchiInput input = new JniInchiInput(options);
101 
102         // Generate atoms
103         JniInchiAtom a1 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
104                 "Cl"));
105         a1.setImplicitProtium(1);
106 
107         return input;
108     }
109 
110     /**
111      * Generates input for hydrogen chloride, with implicit deuterium atom.
112      *
113      * @param options
114      * @return
115      * @throws JniInchiException
116      */
117     private static JniInchiInput getHydrogenChlorideImplicitD(
118             final String options) throws JniInchiException {
119         JniInchiInput input = new JniInchiInput(options);
120 
121         // Generate atoms
122         JniInchiAtom a1 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
123                 "Cl"));
124         a1.setImplicitDeuterium(1);
125 
126         return input;
127     }
128 
129     /**
130      * Generates input for hydrogen chloride, with implicit tritium atom.
131      *
132      * @param options
133      * @return
134      * @throws JniInchiException
135      */
136     private static JniInchiInput getHydrogenChlorideImplicitT(
137             final String options) throws JniInchiException {
138         JniInchiInput input = new JniInchiInput(options);
139 
140         // Generate atoms
141         JniInchiAtom a1 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
142                 "Cl"));
143         a1.setImplicitTritium(1);
144 
145         return input;
146     }
147 
148     /**
149      * Generates input for a 37Cl atom by isotopic mass.
150      *
151      * @param options
152      * @return
153      * @throws JniInchiException
154      */
155     private static JniInchiInput getChlorine37Atom(final String options)
156             throws JniInchiException {
157         JniInchiInput input = new JniInchiInput(options);
158 
159         // Generate atoms
160         JniInchiAtom a1 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
161                 "Cl"));
162         a1.setIsotopicMass(37);
163         a1.setImplicitH(0);
164 
165         return input;
166     }
167 
168     /**
169      * Generates input for a 37Cl atom by isotopic mass shift.
170      *
171      * @param options
172      * @return
173      * @throws JniInchiException
174      */
175     private static JniInchiInput getChlorine37ByIsotopicMassShiftAtom(
176             final String options) throws JniInchiException {
177         JniInchiInput input = new JniInchiInput(options);
178 
179         // Generate atoms
180         JniInchiAtom a1 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
181                 "Cl"));
182         a1.setIsotopicMassShift(+2);
183         input.getAtom(0).setImplicitH(0);
184 
185         return input;
186     }
187 
188     /**
189      * Generates input for a methyl radical, with implicit hydrogens.
190      *
191      * @param options
192      * @return
193      * @throws JniInchiException
194      */
195     private static JniInchiInput getMethylRadical(final String options)
196             throws JniInchiException {
197         JniInchiInput input = new JniInchiInput(options);
198 
199         // Generate atoms
200         JniInchiAtom a1 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
201                 "C"));
202         a1.setImplicitH(3);
203         a1.setRadical(INCHI_RADICAL.DOUBLET);
204 
205         return input;
206     }
207 
208 
209     private static JniInchiInput getSodiumHydroxide(final String options)
210             throws JniInchiException {
211         JniInchiInput input = new JniInchiInput(options);
212 
213         // Generate atoms
214         JniInchiAtom a0 = new JniInchiAtom(0.000, 0.000, 0.000, "Na");
215         input.addAtom(a0);
216         JniInchiAtom a1 = new JniInchiAtom(0.000, 0.000, 0.000, "O");
217         a1.setImplicitH(1);
218         input.addAtom(a1);
219 
220         input.addBond(new JniInchiBond(a0, a1, INCHI_BOND_TYPE.SINGLE));
221 
222         return input;
223     }
224 
225     /**
226      * Generates input for an ethane molecule, with no coordinates and implicit
227      * hydrogens.
228      *
229      * @param options
230      * @return
231      * @throws JniInchiException
232      */
233     private static JniInchiInput getEthane(final String options)
234             throws JniInchiException {
235         JniInchiInput input = new JniInchiInput(options);
236 
237         // Generate atoms
238         JniInchiAtom a1 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
239                 "C"));
240         JniInchiAtom a2 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
241                 "C"));
242         a1.setImplicitH(3);
243         a2.setImplicitH(3);
244 
245         // Add bond
246         input.addBond(new JniInchiBond(a1, a2, INCHI_BOND_TYPE.SINGLE));
247 
248         return input;
249     }
250 
251     /**
252      * Generates input for an ethene molecule, with no coordinates and implicit
253      * hydrogens.
254      *
255      * @param options
256      * @return
257      * @throws JniInchiException
258      */
259     private static JniInchiInput getEthene(final String options)
260             throws JniInchiException {
261         JniInchiInput input = new JniInchiInput(options);
262 
263         // Generate atoms
264         JniInchiAtom a1 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
265                 "C"));
266         JniInchiAtom a2 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
267                 "C"));
268         a1.setImplicitH(2);
269         a2.setImplicitH(2);
270 
271         // Add bond
272         input.addBond(new JniInchiBond(a1, a2, INCHI_BOND_TYPE.DOUBLE));
273 
274         return input;
275     }
276 
277     /**
278      * Generates input for an ethyne molecule, with no coordinates and implicit
279      * hydrogens.
280      *
281      * @param options
282      * @return
283      * @throws JniInchiException
284      */
285     private static JniInchiInput getEthyne(final String options)
286             throws JniInchiException {
287         JniInchiInput input = new JniInchiInput(options);
288 
289         // Generate atoms
290         JniInchiAtom a1 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
291                 "C"));
292         JniInchiAtom a2 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
293                 "C"));
294         a1.setImplicitH(1);
295         a2.setImplicitH(1);
296 
297         // Add bond
298         input.addBond(new JniInchiBond(a1, a2, INCHI_BOND_TYPE.TRIPLE));
299 
300         return input;
301     }
302 
303     /**
304      * Generates input for an (E)-1,2-dichloroethene molecule, with 2D
305      * coordinates and implicit hydrogens.
306      *
307      * @param options
308      * @return
309      * @throws JniInchiException
310      */
311     private static JniInchiInput getE12dichloroethene2D(final String options)
312             throws JniInchiException {
313         JniInchiInput input = new JniInchiInput(options);
314 
315         // Generate atoms
316         JniInchiAtom a1 = input.addAtom(new JniInchiAtom(2.866, -0.250, 0.000,
317                 "C"));
318         JniInchiAtom a2 = input.addAtom(new JniInchiAtom(3.732, 0.250, 0.000,
319                 "C"));
320         JniInchiAtom a3 = input.addAtom(new JniInchiAtom(2.000, 2.500, 0.000,
321                 "Cl"));
322         JniInchiAtom a4 = input.addAtom(new JniInchiAtom(4.598, -0.250, 0.000,
323                 "Cl"));
324         a1.setImplicitH(1);
325         a2.setImplicitH(1);
326 
327         // Add bond
328         input.addBond(new JniInchiBond(a1, a2, INCHI_BOND_TYPE.DOUBLE));
329         input.addBond(new JniInchiBond(a1, a3, INCHI_BOND_TYPE.SINGLE));
330         input.addBond(new JniInchiBond(a2, a4, INCHI_BOND_TYPE.SINGLE));
331 
332         return input;
333     }
334 
335     /**
336      * Generates input for an (E)-1,2-dichloroethene molecule, with 2D
337      * coordinates and implicit hydrogens.
338      *
339      * @param options
340      * @return
341      * @throws JniInchiException
342      */
343     private static JniInchiInput getZ12dichloroethene2D(final String options)
344             throws JniInchiException {
345         JniInchiInput input = new JniInchiInput(options);
346 
347         // Generate atoms
348         JniInchiAtom a1 = input.addAtom(new JniInchiAtom(2.866, -0.440, 0.000,
349                 "C"));
350         JniInchiAtom a2 = input.addAtom(new JniInchiAtom(3.732, 0.060, 0.000,
351                 "C"));
352         JniInchiAtom a3 = input.addAtom(new JniInchiAtom(2.000, 0.060, 0.000,
353                 "Cl"));
354         JniInchiAtom a4 = input.addAtom(new JniInchiAtom(3.732, 1.060, 0.000,
355                 "Cl"));
356         a1.setImplicitH(1);
357         a2.setImplicitH(1);
358 
359         // Add bond
360         input.addBond(new JniInchiBond(a1, a2, INCHI_BOND_TYPE.DOUBLE));
361         input.addBond(new JniInchiBond(a1, a3, INCHI_BOND_TYPE.SINGLE));
362         input.addBond(new JniInchiBond(a2, a4, INCHI_BOND_TYPE.SINGLE));
363 
364         return input;
365     }
366 
367     /**
368      * Generates input for an (E)-1,2-dichloroethene molecule, with 0D
369      * coordinates.
370      *
371      * @param options
372      * @return
373      * @throws JniInchiException
374      */
375     private static JniInchiInput get12dichloroethene0D(final String options)
376             throws JniInchiException {
377         JniInchiInput input = new JniInchiInput(options);
378 
379         // Generate atoms
380         JniInchiAtom a1 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
381                 "C"));
382         JniInchiAtom a2 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
383                 "C"));
384         JniInchiAtom a3 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
385                 "Cl"));
386         JniInchiAtom a4 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
387                 "Cl"));
388         a1.setImplicitH(1);
389         a2.setImplicitH(1);
390 
391         // Add bond
392         input.addBond(new JniInchiBond(a1, a2, INCHI_BOND_TYPE.DOUBLE));
393         input.addBond(new JniInchiBond(a1, a3, INCHI_BOND_TYPE.SINGLE));
394         input.addBond(new JniInchiBond(a2, a4, INCHI_BOND_TYPE.SINGLE));
395 
396         return input;
397     }
398 
399     /**
400      * Generates input for an (E)-1,2-dichloroethene molecule, with 0D
401      * coordinates and stereo parities.
402      *
403      * @param options
404      * @return
405      * @throws JniInchiException
406      */
407     private static JniInchiInput getE12dichloroethene0D(final String options)
408             throws JniInchiException {
409         JniInchiInput input = new JniInchiInput(options);
410 
411         // Generate atoms
412         JniInchiAtom a1 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
413                 "C"));
414         JniInchiAtom a2 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
415                 "C"));
416         JniInchiAtom a3 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
417                 "Cl"));
418         JniInchiAtom a4 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
419                 "Cl"));
420         a1.setImplicitH(1);
421         a2.setImplicitH(1);
422 
423         // Add bond
424         input.addBond(new JniInchiBond(a1, a2, INCHI_BOND_TYPE.DOUBLE));
425         input.addBond(new JniInchiBond(a1, a3, INCHI_BOND_TYPE.SINGLE));
426         input.addBond(new JniInchiBond(a2, a4, INCHI_BOND_TYPE.SINGLE));
427 
428         // Add stereo parities
429         input.addStereo0D(JniInchiStereo0D.createNewDoublebondStereo0D(a3, a1,
430                 a2, a4, INCHI_PARITY.EVEN));
431 
432         return input;
433     }
434 
435     /**
436      * Generates input for an (E)-1,2-dichloroethene molecule, with 2D
437      * coordinates and stereo parities.
438      *
439      * @param options
440      * @return
441      * @throws JniInchiException
442      */
443     private static JniInchiInput getZ12dichloroethene0D(final String options)
444             throws JniInchiException {
445         JniInchiInput input = new JniInchiInput(options);
446 
447         // Generate atoms
448         JniInchiAtom a1 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
449                 "C"));
450         JniInchiAtom a2 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
451                 "C"));
452         JniInchiAtom a3 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
453                 "Cl"));
454         JniInchiAtom a4 = input.addAtom(new JniInchiAtom(0.000, 0.000, 0.000,
455                 "Cl"));
456         a1.setImplicitH(1);
457         a2.setImplicitH(1);
458 
459         // Add bond
460         input.addBond(new JniInchiBond(a1, a2, INCHI_BOND_TYPE.DOUBLE));
461         input.addBond(new JniInchiBond(a1, a3, INCHI_BOND_TYPE.SINGLE));
462         input.addBond(new JniInchiBond(a2, a4, INCHI_BOND_TYPE.SINGLE));
463 
464         // Add stereo parities
465         input.addStereo0D(JniInchiStereo0D.createNewDoublebondStereo0D(a3, a1,
466                 a2, a4, INCHI_PARITY.ODD));
467 
468         return input;
469     }
470 
471     /**
472      * Generates input for L-alanine molecule, with 3D coordinates and implicit
473      * hydrogens.
474      *
475      * @param options
476      * @return
477      * @throws JniInchiException
478      */
479     private static JniInchiInput getLAlanine3D(final String options)
480             throws JniInchiException {
481         JniInchiInput input = new JniInchiInput(options);
482 
483         // Generate atoms
484         JniInchiAtom a1 = input.addAtom(new JniInchiAtom(-0.358, 0.819, 20.655,
485                 "C"));
486         JniInchiAtom a2 = input.addAtom(new JniInchiAtom(-1.598, -0.032,
487                 20.905, "C"));
488         JniInchiAtom a3 = input.addAtom(new JniInchiAtom(-0.275, 2.014, 21.574,
489                 "N"));
490         JniInchiAtom a4 = input.addAtom(new JniInchiAtom(0.952, 0.043, 20.838,
491                 "C"));
492         JniInchiAtom a5 = input.addAtom(new JniInchiAtom(-2.678, 0.479, 21.093,
493                 "O"));
494         JniInchiAtom a6 = input.addAtom(new JniInchiAtom(-1.596, -1.239,
495                 20.958, "O"));
496 
497         a1.setImplicitH(1);
498         a3.setImplicitH(2);
499         a4.setImplicitH(3);
500         a5.setImplicitH(1);
501 
502         // Add bonds
503         input.addBond(new JniInchiBond(a1, a2, INCHI_BOND_TYPE.SINGLE));
504         input.addBond(new JniInchiBond(a1, a3, INCHI_BOND_TYPE.SINGLE));
505         input.addBond(new JniInchiBond(a1, a4, INCHI_BOND_TYPE.SINGLE));
506         input.addBond(new JniInchiBond(a2, a5, INCHI_BOND_TYPE.SINGLE));
507         input.addBond(new JniInchiBond(a2, a6, INCHI_BOND_TYPE.DOUBLE));
508 
509         return input;
510     }
511 
512     /**
513      * Generates input for D-alanine molecule, with 3D coordinates and implicit
514      * hydrogens.
515      *
516      * @param options
517      * @return
518      * @throws JniInchiException
519      */
520     private static JniInchiInput getDAlanine3D(final String options)
521             throws JniInchiException {
522         JniInchiInput input = new JniInchiInput(options);
523 
524         // Generate atoms
525         JniInchiAtom a1 = input.addAtom(new JniInchiAtom(0.358, 0.819, 20.655,
526                 "C"));
527         JniInchiAtom a2 = input.addAtom(new JniInchiAtom(1.598, -0.032, 20.905,
528                 "C"));
529         JniInchiAtom a3 = input.addAtom(new JniInchiAtom(0.275, 2.014, 21.574,
530                 "N"));
531         JniInchiAtom a4 = input.addAtom(new JniInchiAtom(-0.952, 0.043, 20.838,
532                 "C"));
533         JniInchiAtom a5 = input.addAtom(new JniInchiAtom(2.678, 0.479, 21.093,
534                 "O"));
535         JniInchiAtom a6 = input.addAtom(new JniInchiAtom(1.596, -1.239, 20.958,
536                 "O"));
537 
538         a1.setImplicitH(1);
539         a3.setImplicitH(2);
540         a4.setImplicitH(3);
541         a5.setImplicitH(1);
542 
543         // Add bonds
544         input.addBond(new JniInchiBond(a1, a2, INCHI_BOND_TYPE.SINGLE));
545         input.addBond(new JniInchiBond(a1, a3, INCHI_BOND_TYPE.SINGLE));
546         input.addBond(new JniInchiBond(a1, a4, INCHI_BOND_TYPE.SINGLE));
547         input.addBond(new JniInchiBond(a2, a5, INCHI_BOND_TYPE.SINGLE));
548         input.addBond(new JniInchiBond(a2, a6, INCHI_BOND_TYPE.DOUBLE));
549 
550         return input;
551     }
552 
553     /**
554      * Generates input for alanine molecule, with 2D coordinates.
555      *
556      * @param options
557      * @return
558      * @throws JniInchiException
559      */
560     private static JniInchiInput getAlanine2D(final String options)
561             throws JniInchiException {
562         JniInchiInput input = new JniInchiInput(options);
563 
564         // Generate atoms
565         JniInchiAtom a1 = input
566                 .addAtom(new JniInchiAtom(264.0, 968.0, 0.0, "C"));
567         JniInchiAtom a2 = input
568                 .addAtom(new JniInchiAtom(295.0, 985.0, 0.0, "C"));
569         JniInchiAtom a3 = input
570                 .addAtom(new JniInchiAtom(233.0, 986.0, 0.0, "N"));
571         JniInchiAtom a4 = input
572                 .addAtom(new JniInchiAtom(264.0, 932.0, 0.0, "C"));
573         JniInchiAtom a5 = input
574                 .addAtom(new JniInchiAtom(326.0, 967.0, 0.0, "O"));
575         JniInchiAtom a6 = input.addAtom(new JniInchiAtom(295.0, 1021.0, 0.0,
576                 "O"));
577 
578         a1.setImplicitH(1);
579         a3.setImplicitH(2);
580         a4.setImplicitH(3);
581         a5.setImplicitH(1);
582 
583         // Add bonds
584         input.addBond(new JniInchiBond(a1, a2, INCHI_BOND_TYPE.SINGLE));
585         input.addBond(new JniInchiBond(a1, a3, INCHI_BOND_TYPE.SINGLE));
586         input.addBond(new JniInchiBond(a1, a4, INCHI_BOND_TYPE.SINGLE));
587         input.addBond(new JniInchiBond(a2, a5, INCHI_BOND_TYPE.SINGLE));
588         input.addBond(new JniInchiBond(a2, a6, INCHI_BOND_TYPE.DOUBLE));
589 
590         return input;
591     }
592 
593     /**
594      * Generates input for L-alanine molecule, with 2D coordinates and bond
595      * stereo definitions.
596      *
597      * @param options
598      * @return
599      * @throws JniInchiException
600      */
601     private static JniInchiInput getLAlanine2Da(final String options)
602             throws JniInchiException {
603         JniInchiInput input = new JniInchiInput(options);
604 
605         // Generate atoms
606         JniInchiAtom a1 = input
607                 .addAtom(new JniInchiAtom(264.0, 968.0, 0.0, "C"));
608         JniInchiAtom a2 = input
609                 .addAtom(new JniInchiAtom(295.0, 985.0, 0.0, "C"));
610         JniInchiAtom a3 = input
611                 .addAtom(new JniInchiAtom(233.0, 986.0, 0.0, "N"));
612         JniInchiAtom a4 = input
613                 .addAtom(new JniInchiAtom(264.0, 932.0, 0.0, "C"));
614         JniInchiAtom a5 = input
615                 .addAtom(new JniInchiAtom(326.0, 967.0, 0.0, "O"));
616         JniInchiAtom a6 = input.addAtom(new JniInchiAtom(295.0, 1021.0, 0.0,
617                 "O"));
618 
619         a1.setImplicitH(1);
620         a3.setImplicitH(2);
621         a4.setImplicitH(3);
622         a5.setImplicitH(1);
623 
624         // Add bonds
625         input.addBond(new JniInchiBond(a1, a2, INCHI_BOND_TYPE.SINGLE));
626         input.addBond(new JniInchiBond(a1, a3, INCHI_BOND_TYPE.SINGLE))
627                 .setStereoDefinition(INCHI_BOND_STEREO.SINGLE_1DOWN);
628         input.addBond(new JniInchiBond(a1, a4, INCHI_BOND_TYPE.SINGLE));
629         input.addBond(new JniInchiBond(a2, a5, INCHI_BOND_TYPE.SINGLE));
630         input.addBond(new JniInchiBond(a2, a6, INCHI_BOND_TYPE.DOUBLE));
631 
632         return input;
633     }
634 
635 
636     private static JniInchiInput getLAlanine2Db(final String options)
637             throws JniInchiException {
638         JniInchiInput input = new JniInchiInput(options);
639 
640         // Generate atoms
641         JniInchiAtom a1 = input
642                 .addAtom(new JniInchiAtom(264.0, 968.0, 0.0, "C"));
643         JniInchiAtom a2 = input
644                 .addAtom(new JniInchiAtom(295.0, 985.0, 0.0, "C"));
645         JniInchiAtom a3 = input
646                 .addAtom(new JniInchiAtom(233.0, 986.0, 0.0, "N"));
647         JniInchiAtom a4 = input
648                 .addAtom(new JniInchiAtom(264.0, 932.0, 0.0, "C"));
649         JniInchiAtom a5 = input
650                 .addAtom(new JniInchiAtom(326.0, 967.0, 0.0, "O"));
651         JniInchiAtom a6 = input.addAtom(new JniInchiAtom(295.0, 1021.0, 0.0,
652                 "O"));
653 
654         a1.setImplicitH(1);
655         a3.setImplicitH(2);
656         a4.setImplicitH(3);
657         a5.setImplicitH(1);
658 
659         // Add bonds
660         input.addBond(new JniInchiBond(a1, a2, INCHI_BOND_TYPE.SINGLE));
661         input.addBond(new JniInchiBond(a3, a1, INCHI_BOND_TYPE.SINGLE));
662         input.addBond(new JniInchiBond(a1, a4, INCHI_BOND_TYPE.SINGLE))
663                 .setStereoDefinition(INCHI_BOND_STEREO.SINGLE_1DOWN);
664         input.addBond(new JniInchiBond(a2, a5, INCHI_BOND_TYPE.SINGLE));
665         input.addBond(new JniInchiBond(a2, a6, INCHI_BOND_TYPE.DOUBLE));
666 
667         return input;
668     }
669 
670     /**
671      * Generates input for D-alanine molecule, with 2D coordinates and bond
672      * stereo definitions.
673      *
674      * @param options
675      * @return
676      * @throws JniInchiException
677      */
678     private static JniInchiInput getDAlanine2D(final String options)
679             throws JniInchiException {
680         JniInchiInput input = new JniInchiInput(options);
681 
682         // Generate atoms
683         JniInchiAtom a1 = input
684                 .addAtom(new JniInchiAtom(264.0, 968.0, 0.0, "C"));
685         JniInchiAtom a2 = input
686                 .addAtom(new JniInchiAtom(295.0, 985.0, 0.0, "C"));
687         JniInchiAtom a3 = input
688                 .addAtom(new JniInchiAtom(233.0, 986.0, 0.0, "N"));
689         JniInchiAtom a4 = input
690                 .addAtom(new JniInchiAtom(264.0, 932.0, 0.0, "C"));
691         JniInchiAtom a5 = input
692                 .addAtom(new JniInchiAtom(326.0, 967.0, 0.0, "O"));
693         JniInchiAtom a6 = input.addAtom(new JniInchiAtom(295.0, 1021.0, 0.0,
694                 "O"));
695 
696         a1.setImplicitH(1);
697         a3.setImplicitH(2);
698         a4.setImplicitH(3);
699         a5.setImplicitH(1);
700 
701         // Add bonds
702         input.addBond(new JniInchiBond(a1, a2, INCHI_BOND_TYPE.SINGLE));
703         input.addBond(new JniInchiBond(a1, a3, INCHI_BOND_TYPE.SINGLE))
704                 .setStereoDefinition(INCHI_BOND_STEREO.SINGLE_1UP);
705         input.addBond(new JniInchiBond(a1, a4, INCHI_BOND_TYPE.SINGLE));
706         input.addBond(new JniInchiBond(a2, a5, INCHI_BOND_TYPE.SINGLE));
707         input.addBond(new JniInchiBond(a2, a6, INCHI_BOND_TYPE.DOUBLE));
708 
709         return input;
710     }
711 
712     /**
713      * Generates input for alanine molecule with no coordinates.
714      *
715      * @param options
716      * @return
717      * @throws JniInchiException
718      */
719     private static JniInchiInput getAlanine0D(final String options)
720             throws JniInchiException {
721         JniInchiInput input = new JniInchiInput(options);
722 
723         // Generate atoms
724         JniInchiAtom a0 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "C"));
725         JniInchiAtom a1 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "C"));
726         JniInchiAtom a2 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "N"));
727         JniInchiAtom a3 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "C"));
728         JniInchiAtom a4 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "O"));
729         JniInchiAtom a5 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "O"));
730         JniInchiAtom a6 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "H"));
731         a2.setImplicitH(2);
732         a3.setImplicitH(3);
733         a4.setImplicitH(1);
734 
735         // Add bonds
736         input.addBond(new JniInchiBond(a0, a1, INCHI_BOND_TYPE.SINGLE));
737         input.addBond(new JniInchiBond(a0, a2, INCHI_BOND_TYPE.SINGLE));
738         input.addBond(new JniInchiBond(a0, a3, INCHI_BOND_TYPE.SINGLE));
739         input.addBond(new JniInchiBond(a1, a4, INCHI_BOND_TYPE.SINGLE));
740         input.addBond(new JniInchiBond(a1, a5, INCHI_BOND_TYPE.DOUBLE));
741         input.addBond(new JniInchiBond(a0, a6, INCHI_BOND_TYPE.SINGLE));
742 
743         return input;
744     }
745 
746     /**
747      * Generates input for L-alanine molecule with no coordinates but 0D stereo
748      * parities.
749      *
750      * @param options
751      * @return
752      * @throws JniInchiException
753      */
754     private static JniInchiInput getLAlanine0D(final String options)
755             throws JniInchiException {
756         JniInchiInput input = new JniInchiInput(options);
757 
758         // Generate atoms
759         JniInchiAtom a1 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "C"));
760         JniInchiAtom a2 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "C"));
761         JniInchiAtom a3 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "N"));
762         JniInchiAtom a4 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "C"));
763         JniInchiAtom a5 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "O"));
764         JniInchiAtom a6 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "O"));
765         JniInchiAtom a7 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "H"));
766         a3.setImplicitH(2);
767         a4.setImplicitH(3);
768         a5.setImplicitH(1);
769 
770         // Add bonds
771         input.addBond(new JniInchiBond(a1, a2, INCHI_BOND_TYPE.SINGLE));
772         input.addBond(new JniInchiBond(a1, a3, INCHI_BOND_TYPE.SINGLE));
773         input.addBond(new JniInchiBond(a1, a4, INCHI_BOND_TYPE.SINGLE));
774         input.addBond(new JniInchiBond(a2, a5, INCHI_BOND_TYPE.SINGLE));
775         input.addBond(new JniInchiBond(a2, a6, INCHI_BOND_TYPE.DOUBLE));
776         input.addBond(new JniInchiBond(a1, a7, INCHI_BOND_TYPE.SINGLE));
777 
778         // Add stereo parities
779         input.addStereo0D(JniInchiStereo0D.createNewTetrahedralStereo0D(a1, a3,
780                 a4, a7, a2, INCHI_PARITY.ODD));
781 
782         return input;
783     }
784 
785     /**
786      * Generates input for D-alanine molecule with no coordinates but 0D stereo
787      * parities.
788      *
789      * @param options
790      * @return
791      * @throws JniInchiException
792      */
793     private static JniInchiInput getDAlanine0D(final String options)
794             throws JniInchiException {
795         JniInchiInput input = new JniInchiInput(options);
796 
797         // Generate atoms
798         JniInchiAtom a1 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "C"));
799         JniInchiAtom a2 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "C"));
800         JniInchiAtom a3 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "N"));
801         JniInchiAtom a4 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "C"));
802         JniInchiAtom a5 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "O"));
803         JniInchiAtom a6 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "O"));
804         JniInchiAtom a7 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "H"));
805         a3.setImplicitH(2);
806         a4.setImplicitH(3);
807         a5.setImplicitH(1);
808 
809         // Add bonds
810         input.addBond(new JniInchiBond(a1, a2, INCHI_BOND_TYPE.SINGLE));
811         input.addBond(new JniInchiBond(a1, a3, INCHI_BOND_TYPE.SINGLE));
812         input.addBond(new JniInchiBond(a1, a4, INCHI_BOND_TYPE.SINGLE));
813         input.addBond(new JniInchiBond(a2, a5, INCHI_BOND_TYPE.SINGLE));
814         input.addBond(new JniInchiBond(a2, a6, INCHI_BOND_TYPE.DOUBLE));
815         input.addBond(new JniInchiBond(a1, a7, INCHI_BOND_TYPE.SINGLE));
816 
817         // Add stereo parities
818         input.addStereo0D(JniInchiStereo0D.createNewTetrahedralStereo0D(a1, a3,
819                 a4, a7, a2, INCHI_PARITY.EVEN));
820         return input;
821     }
822 
823 
824     private JniInchiInput getNSC7414a(String options) throws JniInchiException {
825 
826         JniInchiInput input = new JniInchiInput(options);
827 
828         // Generate atoms
829         JniInchiAtom a1 = input.addAtom(new JniInchiAtom(-1.1292, -0.5292, 0.0, "C"));
830         JniInchiAtom a2 = input.addAtom(new JniInchiAtom(-1.1333, -1.5917, 0.0, "C"));
831         JniInchiAtom a3 = input.addAtom(new JniInchiAtom(-1.1333, 0.5333, 0.0, "C"));
832         JniInchiAtom a4 = input.addAtom(new JniInchiAtom(-1.1375, -2.6542, 0.0, "C"));
833         JniInchiAtom a5 = input.addAtom(new JniInchiAtom(0.8375, 0.5625, 0.0, "C"));
834         JniInchiAtom a6 = input.addAtom(new JniInchiAtom(0.9917, -2.4667, 0.0, "C"));
835         JniInchiAtom a7 = input.addAtom(new JniInchiAtom(2.2417, -0.6542, 0.0, "C"));
836         JniInchiAtom a8 = input.addAtom(new JniInchiAtom(4.3000, -0.5000, 0.0, "C"));
837         JniInchiAtom a9 = input.addAtom(new JniInchiAtom(5.8583, 0.9667, 0.0, "C"));
838         JniInchiAtom a10 = input.addAtom(new JniInchiAtom(6.0167, -1.7500, 0.0, "C"));
839         JniInchiAtom a11 = input.addAtom(new JniInchiAtom(6.2042, -3.3417, 0.0, "C"));
840         a1.setImplicitH(-1);
841         a2.setImplicitH(-1);
842         a3.setImplicitH(-1);
843         a4.setImplicitH(-1);
844         a5.setImplicitH(-1);
845         a6.setImplicitH(-1);
846         a7.setImplicitH(-1);
847         a8.setImplicitH(-1);
848         a9.setImplicitH(-1);
849         a10.setImplicitH(-1);
850         a11.setImplicitH(-1);
851 
852         input.addBond(new JniInchiBond(a6, a4, INCHI_BOND_TYPE.SINGLE));
853         input.addBond(new JniInchiBond(a1, a2, INCHI_BOND_TYPE.DOUBLE));
854         input.addBond(new JniInchiBond(a7, a5, INCHI_BOND_TYPE.SINGLE));
855         input.addBond(new JniInchiBond(a7, a6, INCHI_BOND_TYPE.SINGLE));
856         input.addBond(new JniInchiBond(a2, a4, INCHI_BOND_TYPE.SINGLE));
857         input.addBond(new JniInchiBond(a8, a7, INCHI_BOND_TYPE.SINGLE));
858         input.addBond(new JniInchiBond(a9, a8, INCHI_BOND_TYPE.SINGLE));
859         input.addBond(new JniInchiBond(a5, a3, INCHI_BOND_TYPE.SINGLE));
860         input.addBond(new JniInchiBond(a8, a10, INCHI_BOND_TYPE.SINGLE));
861         input.addBond(new JniInchiBond(a1, a3, INCHI_BOND_TYPE.SINGLE));
862         input.addBond(new JniInchiBond(a11, a10, INCHI_BOND_TYPE.SINGLE));
863 
864 //        input.addStereo0D(new JniInchiStereo0D(a7, a7, a5, a6, a8, INCHI_STEREOTYPE.TETRAHEDRAL, INCHI_PARITY.EVEN));
865 //        input.addStereo0D(new JniInchiStereo0D(a8, a8, a7, a9, a10, INCHI_STEREOTYPE.TETRAHEDRAL, INCHI_PARITY.ODD));
866 
867         return input;
868     }
869 
870     /*
871      *
872 
873 
874   -ClnMol-06180618052D
875 
876 11 11  0  0  0  0  0  0  0  0999 V2000
877    -1.1292   -0.5292    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0	1
878    -1.1333   -1.5917    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0	2
879    -1.1333    0.5333    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0	3
880    -1.1375   -2.6542    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0	4
881     0.8375    0.5625    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0	5
882     0.9917   -2.4667    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0	6
883     2.2417   -0.6542    0.0000 C   0  0  2  0  0  0  0  0  0  0  0  0	7
884     4.3000   -0.5000    0.0000 C   0  0  1  0  0  0  0  0  0  0  0  0	8
885     5.8583    0.9667    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0	9
886     6.0167   -1.7500    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0	10
887     6.2042   -3.3417    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0	11
888   6  4  1  0  0  0  0
889   1  2  2  0  0  0  0
890   7  5  1  1  0  0  0
891   7  6  1  1  0  0  0
892   2  4  1  0  0  0  0
893   8  7  1  0  0  0  0
894   9  8  1  1  0  0  0
895   5  3  1  0  0  0  0
896   8 10  1  1  0  0  0
897   1  3  1  0  0  0  0
898 11 10  1  0  0  0  0
899 M  END
900 >  <ID>
901 NSC-7414a
902 
903      *
904      *
905      */
906 
907     // Test atom handling
908 
909     /**
910      * Tests element name is correctly passed to InChI.
911      *
912      * @throws Exception
913      */
914     @Test
915     public void testGetInchiFromChlorineAtom() throws Exception {
916         JniInchiInput input = getChlorineAtom("");
917         JniInchiOutput output = JniInchiWrapper.getInchi(input);
918         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
919         assertEquals("InChI=1S/Cl", output.getInchi());
920     }
921 
922     /**
923      * Tests charge is correctly passed to InChI.
924      *
925      * @throws Exception
926      */
927     @Test
928     public void testGetInchiFromChlorineIon() throws Exception {
929         JniInchiInput input = getChlorineIon("");
930         JniInchiOutput output = JniInchiWrapper.getInchi(input);
931         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
932         assertEquals("InChI=1S/Cl/q-1", output.getInchi());
933     }
934 
935     /**
936      * Tests isotopic mass is correctly passed to InChI.
937      *
938      * @throws Exception
939      */
940     @Test
941     public void testGetInchiFromChlorine37Atom() throws Exception {
942         JniInchiInput input = getChlorine37Atom("");
943         JniInchiOutput output = JniInchiWrapper.getInchi(input);
944         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
945         assertEquals("InChI=1S/Cl/i1+2", output.getInchi());
946     }
947 
948     /**
949      * Tests isotopic mass shift is correctly passed to InChI.
950      *
951      * @throws Exception
952      */
953     @Test
954     public void testGetInchiFromChlorine37ByIstopicMassShiftAtom()
955             throws Exception {
956         JniInchiInput input = getChlorine37ByIsotopicMassShiftAtom("");
957         JniInchiOutput output = JniInchiWrapper.getInchi(input);
958         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
959         assertEquals("InChI=1S/Cl/i1+2", output.getInchi());
960     }
961 
962 
963     @Test
964     public void testGetInchiFromSodiumHydroxide() throws Exception {
965         JniInchiInput input = getSodiumHydroxide("");
966         JniInchiOutput output = JniInchiWrapper.getInchi(input);
967         assertEquals("InChI=1S/Na.H2O/h;1H2/q+1;/p-1", output.getInchi());
968         assertEquals(INCHI_RET.WARNING, output.getReturnStatus());
969         assertEquals("Metal was disconnected; Proton(s) added/removed", output.getMessage());
970     }
971 
972     /**
973      * Tests implicit hydrogen count is correctly passed to InChI.
974      *
975      * @throws Exception
976      */
977     @Test
978     public void testGetInchiFromHydrogenChlorideImplicitH() throws Exception {
979         JniInchiInput input = getHydrogenChlorideImplicitH("");
980         JniInchiOutput output = JniInchiWrapper.getInchi(input);
981         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
982         assertEquals("InChI=1S/ClH/h1H", output.getInchi());
983     }
984 
985     /**
986      * Tests implicit protium count is correctly passed to InChI.
987      *
988      * @throws Exception
989      */
990     @Test
991     public void testGetInchiFromHydrogenChlorideImplicitP() throws Exception {
992         JniInchiInput input = getHydrogenChlorideImplicitP("");
993         JniInchiOutput output = JniInchiWrapper.getInchi(input);
994         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
995         assertEquals("InChI=1S/ClH/h1H/i/hH", output.getInchi());
996     }
997 
998     /**
999      * Tests implicit deuterium count is correctly passed to InChi.
1000      *
1001      * @throws Exception
1002      */
1003     @Test
1004     public void testGetInchiFromHydrogenChlorideImplicitD() throws Exception {
1005         JniInchiInput input = getHydrogenChlorideImplicitD("");
1006         JniInchiOutput output = JniInchiWrapper.getInchi(input);
1007         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1008         assertEquals("InChI=1S/ClH/h1H/i/hD", output.getInchi());
1009     }
1010 
1011     /**
1012      * Tests implicit tritium count is correctly passed to InChI.
1013      *
1014      * @throws Exception
1015      */
1016     @Test
1017     public void testGetInchiFromHydrogenChlorideImplicitT() throws Exception {
1018         JniInchiInput input = getHydrogenChlorideImplicitT("");
1019         JniInchiOutput output = JniInchiWrapper.getInchi(input);
1020         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1021         assertEquals("InChI=1S/ClH/h1H/i/hT", output.getInchi());
1022     }
1023 
1024     /**
1025      * Tests radical state is correctly passed to InChI.
1026      *
1027      * @throws Exception
1028      */
1029     @Test
1030     public void testGetInchiFromMethylRadical() throws Exception {
1031         JniInchiInput input = getMethylRadical("");
1032         JniInchiOutput output = JniInchiWrapper.getInchi(input);
1033         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1034         assertEquals("InChI=1S/CH3/h1H3", output.getInchi());
1035     }
1036 
1037     // Test bond handling
1038 
1039     /**
1040      * Tests single bond is correctly passed to InChI.
1041      *
1042      * @throws Exception
1043      */
1044     @Test
1045     public void testGetInchiFromEthane() throws Exception {
1046         JniInchiInput input = getEthane("");
1047         JniInchiOutput output = JniInchiWrapper.getInchi(input);
1048         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1049         assertEquals("InChI=1S/C2H6/c1-2/h1-2H3", output.getInchi());
1050     }
1051 
1052     /**
1053      * Tests double bond is correctly passed to InChI.
1054      *
1055      * @throws Exception
1056      */
1057     @Test
1058     public void testGetInchiFromEthene() throws Exception {
1059         JniInchiInput input = getEthene("");
1060         JniInchiOutput output = JniInchiWrapper.getInchi(input);
1061         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1062         assertEquals("InChI=1S/C2H4/c1-2/h1-2H2", output.getInchi());
1063     }
1064 
1065     /**
1066      * Tests triple bond is correctly passed to InChI.
1067      *
1068      * @throws Exception
1069      */
1070     @Test
1071     public void testGetInchiFromEthyne() throws Exception {
1072         JniInchiInput input = getEthyne("");
1073         JniInchiOutput output = JniInchiWrapper.getInchi(input);
1074         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1075         assertEquals("InChI=1S/C2H2/c1-2/h1-2H", output.getInchi());
1076     }
1077 
1078     // Test 2D coordinate handling
1079 
1080     /**
1081      * Tests 2D coordinates are correctly passed to InChI.
1082      *
1083      * @throws Exception
1084      */
1085     @Test
1086     public void testGetInchiEandZ12Dichloroethene2D() throws Exception {
1087         JniInchiInput inputE = getE12dichloroethene2D("");
1088         JniInchiOutput outputE = JniInchiWrapper.getInchi(inputE);
1089         assertEquals(INCHI_RET.OKAY, outputE.getReturnStatus());
1090         assertEquals("InChI=1S/C2H2Cl2/c3-1-2-4/h1-2H/b2-1+", outputE
1091                 .getInchi());
1092 
1093         JniInchiInput inputZ = getZ12dichloroethene2D("");
1094         JniInchiOutput outputZ = JniInchiWrapper.getInchi(inputZ);
1095         assertEquals(INCHI_RET.OKAY, outputZ.getReturnStatus());
1096         assertEquals("InChI=1S/C2H2Cl2/c3-1-2-4/h1-2H/b2-1-", outputZ
1097                 .getInchi());
1098     }
1099 
1100     // Test 3D coordinate handling
1101 
1102     /**
1103      * Tests InChI generation from L and D-Alanine molecules, with 3D
1104      * coordinates.
1105      *
1106      * @throws Exception
1107      */
1108     @Test
1109     public void testGetInchiFromLandDAlanine3D() throws Exception {
1110         JniInchiInput inputL = getLAlanine3D("");
1111         JniInchiOutput outputL = JniInchiWrapper.getInchi(inputL);
1112         assertEquals(INCHI_RET.OKAY, outputL.getReturnStatus());
1113         assertEquals(
1114                 "InChI=1S/C3H7NO2/c1-2(4)3(5)6/h2H,4H2,1H3,(H,5,6)/t2-/m0/s1",
1115                 outputL.getInchi());
1116 
1117         JniInchiInput inputD = getDAlanine3D("");
1118         JniInchiOutput outputD = JniInchiWrapper.getInchi(inputD);
1119         assertEquals(INCHI_RET.OKAY, outputD.getReturnStatus());
1120         assertEquals(
1121                 "InChI=1S/C3H7NO2/c1-2(4)3(5)6/h2H,4H2,1H3,(H,5,6)/t2-/m1/s1",
1122                 outputD.getInchi());
1123     };
1124 
1125     // Test handling of 2D coordinates with bond stereo types
1126 
1127     /**
1128      * Tests InChI generation from L and D-Alanine molecules, with 3D
1129      * coordinates, using FixSp3Bug option from InChI software v1.01
1130      *
1131      * @throws Exception
1132      */
1133     @Test
1134     public void testGetInchiFromAlanine2D() throws Exception {
1135         JniInchiInput input = getAlanine2D("");
1136         JniInchiOutput output = JniInchiWrapper.getInchi(input);
1137         assertEquals(INCHI_RET.WARNING, output.getReturnStatus());
1138         assertEquals("Omitted undefined stereo", output.getMessage());
1139         assertEquals("InChI=1S/C3H7NO2/c1-2(4)3(5)6/h2H,4H2,1H3,(H,5,6)",
1140                 output.getInchi());
1141     }
1142 
1143     @Test
1144     public void testGetInchiFromLAlanine2D() throws Exception {
1145         JniInchiInput inputL = getLAlanine2Da("");
1146         JniInchiOutput outputL = JniInchiWrapper.getInchi(inputL);
1147         assertEquals(INCHI_RET.OKAY, outputL.getReturnStatus());
1148         assertEquals(
1149                 "InChI=1S/C3H7NO2/c1-2(4)3(5)6/h2H,4H2,1H3,(H,5,6)/t2-/m0/s1",
1150                 outputL.getInchi());
1151     }
1152 
1153     @Test
1154     public void testGetInchiFromDAlanine2D() throws Exception {
1155         JniInchiInput inputD = getDAlanine2D("");
1156         JniInchiOutput outputD = JniInchiWrapper.getInchi(inputD);
1157         assertEquals(INCHI_RET.OKAY, outputD.getReturnStatus());
1158         assertEquals(
1159                 "InChI=1S/C3H7NO2/c1-2(4)3(5)6/h2H,4H2,1H3,(H,5,6)/t2-/m1/s1",
1160                 outputD.getInchi());
1161     };
1162 
1163 
1164     /**
1165      * Tests InChI generation from L-Alanine molecules, with 2D coordinates
1166      * and wedge/hatch bonds, with bond drawn in opposite directions.
1167      *
1168      * @throws Exception
1169      */
1170     @Test
1171     public void testGetInchiStereoBondDirection1() throws Exception {
1172         JniInchiInput input = getLAlanine2Da("");
1173         JniInchiOutput output = JniInchiWrapper.getInchi(input);
1174         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1175         assertEquals(
1176                 "InChI=1S/C3H7NO2/c1-2(4)3(5)6/h2H,4H2,1H3,(H,5,6)/t2-/m0/s1",
1177                 output.getInchi());
1178     }
1179 
1180     @Test
1181     public void testGetInchiStereoBondDirection2() throws Exception {
1182         JniInchiInput inputL = getLAlanine2Db("");
1183         JniInchiOutput outputL = JniInchiWrapper.getInchi(inputL);
1184         assertEquals(INCHI_RET.OKAY, outputL.getReturnStatus());
1185         assertEquals(
1186                 "InChI=1S/C3H7NO2/c1-2(4)3(5)6/h2H,4H2,1H3,(H,5,6)/t2-/m0/s1",
1187                 outputL.getInchi());
1188     }
1189 
1190     // Test handling of no coordinates, with stereo parities
1191 
1192     /**
1193      * Tests InChI generation from L and D-Alanine molecules, with no
1194      * coordinates but tetrahedral stereo parities.
1195      *
1196      * @throws Exception
1197      */
1198     @Test
1199     public void testGetInchiFromLandDAlanine0D() throws Exception {
1200         JniInchiInput input = getAlanine0D("");
1201         JniInchiOutput output = JniInchiWrapper.getInchi(input);
1202         assertEquals(INCHI_RET.WARNING, output.getReturnStatus());
1203         assertEquals("Omitted undefined stereo", output.getMessage());
1204         assertEquals("InChI=1S/C3H7NO2/c1-2(4)3(5)6/h2H,4H2,1H3,(H,5,6)",
1205                 output.getInchi());
1206 
1207         JniInchiInput inputL = getLAlanine0D("");
1208         JniInchiOutput outputL = JniInchiWrapper.getInchi(inputL);
1209         assertEquals(INCHI_RET.OKAY, outputL.getReturnStatus());
1210         assertEquals(
1211                 "InChI=1S/C3H7NO2/c1-2(4)3(5)6/h2H,4H2,1H3,(H,5,6)/t2-/m0/s1",
1212                 outputL.getInchi());
1213 
1214         JniInchiInput inputD = getDAlanine0D("");
1215         JniInchiOutput outputD = JniInchiWrapper.getInchi(inputD);
1216         assertEquals(INCHI_RET.OKAY, outputD.getReturnStatus());
1217         assertEquals(
1218                 "InChI=1S/C3H7NO2/c1-2(4)3(5)6/h2H,4H2,1H3,(H,5,6)/t2-/m1/s1",
1219                 outputD.getInchi());
1220     };
1221 
1222     /**
1223      * Tests InChI generation from E and Z 1,2-dichloroethene molecules, with no
1224      * coordinates but doublebond stereo parities.
1225      *
1226      * @throws Exception
1227      */
1228     @Test
1229     public void testGetInchiEandZ12Dichloroethene0D() throws Exception {
1230         JniInchiInput input = get12dichloroethene0D("");
1231         JniInchiOutput output = JniInchiWrapper.getInchi(input);
1232         assertEquals(INCHI_RET.WARNING, output.getReturnStatus());
1233         assertEquals("Omitted undefined stereo", output.getMessage());
1234         Assert
1235                 .assertEquals("InChI=1S/C2H2Cl2/c3-1-2-4/h1-2H", output
1236                         .getInchi());
1237 
1238         JniInchiInput inputE = getE12dichloroethene0D("");
1239         JniInchiOutput outputE = JniInchiWrapper.getInchi(inputE);
1240         assertEquals(INCHI_RET.OKAY, outputE.getReturnStatus());
1241         assertEquals("InChI=1S/C2H2Cl2/c3-1-2-4/h1-2H/b2-1+", outputE
1242                 .getInchi());
1243 
1244         JniInchiInput inputZ = getZ12dichloroethene0D("");
1245         JniInchiOutput outputZ = JniInchiWrapper.getInchi(inputZ);
1246         assertEquals(INCHI_RET.OKAY, outputZ.getReturnStatus());
1247         assertEquals("InChI=1S/C2H2Cl2/c3-1-2-4/h1-2H/b2-1-", outputZ
1248                 .getInchi());
1249     };
1250 
1251 
1252 
1253     @Test
1254     public void testGetInchiFromNSC7414a() throws JniInchiException {
1255         JniInchiInput input = getNSC7414a("");
1256         JniInchiOutput output = JniInchiWrapper.getInchi(input);
1257         assertEquals(INCHI_RET.WARNING, output.getReturnStatus());
1258         assertEquals("Omitted undefined stereo", output.getMessage());
1259         assertEquals(
1260                 "InChI=1S/C11H20/c1-3-10(2)11-8-6-4-5-7-9-11/h4-5,10-11H,3,6-9H2,1-2H3",
1261                 output.getInchi());
1262     }
1263 
1264 
1265 
1266     // Test option checking
1267 
1268     /**
1269      * Tests option lists are canonicalised correctly.
1270      */
1271     @SuppressWarnings("unchecked")
1272     @Test
1273     public void testCheckOptionsList() throws JniInchiException {
1274         List opList = new ArrayList();
1275         opList.add(INCHI_OPTION.Compress);
1276         opList.add(INCHI_OPTION.SNon);
1277         String options = JniInchiWrapper.checkOptions(opList);
1278         String flag = JniInchiWrapper.flagChar;
1279         assertEquals(flag + "Compress " + flag + "SNon ", options);
1280     }
1281 
1282     /**
1283      * Tests option strings are handled checked canonicalised.
1284      *
1285      * @throws JniInchiException
1286      */
1287     @Test
1288     public void testCheckOptionsString() throws JniInchiException {
1289         String options = JniInchiWrapper.checkOptions("  -ComPreSS  /SNon");
1290         String flag = JniInchiWrapper.flagChar;
1291         assertEquals(flag + "Compress " + flag + "SNon", options);
1292     }
1293 
1294     // Test option handling
1295 
1296     /**
1297      * Tests passing options to inchi.
1298      *
1299      * @throws Exception
1300      */
1301     // @Test
1302     public void testGetInchiWithOptions() throws Exception {
1303         JniInchiInput input = getLAlanine3D("");
1304         JniInchiOutput output = JniInchiWrapper.getInchi(input);
1305         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1306         assertEquals(
1307                 "InChI=1/C3H7NO2/c1-2(4)3(5)6/h2H,4H2,1H3,(H,5,6)/t2-/m0/s1",
1308                 output.getInchi());
1309 
1310         input = getLAlanine3D("-compress");
1311         output = JniInchiWrapper.getInchi(input);
1312         // debug(output);
1313         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1314         assertEquals("InChI=1/C3H7NO2/cABBCC/hB1D2A3,1EF/tB1/m0/s1",
1315                 output.getInchi());
1316 
1317         input = getLAlanine3D("/compress");
1318         output = JniInchiWrapper.getInchi(input);
1319         // debug(output);
1320         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1321         assertEquals("InChI=1/C3H7NO2/cABBCC/hB1D2A3,1EF/tB1/m0/s1",
1322                 output.getInchi());
1323 
1324         input = getLAlanine3D("-cOMprEsS");
1325         output = JniInchiWrapper.getInchi(input);
1326         // debug(output);
1327         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1328         assertEquals("InChI=1/C3H7NO2/cABBCC/hB1D2A3,1EF/tB1/m0/s1",
1329                 output.getInchi());
1330     }
1331 
1332     // Test structure generation from InChI strings
1333 
1334     /**
1335      * Tests element name is correctly read from InChI.
1336      *
1337      * @throws Exception
1338      */
1339     @Test
1340     public void testGetChlorineAtomFromInchi() throws Exception {
1341         JniInchiInputInchi input = new JniInchiInputInchi("InChI=1/Cl");
1342         JniInchiOutputStructure output = JniInchiWrapper
1343                 .getStructureFromInchi(input);
1344         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1345         assertEquals(1, output.getNumAtoms());
1346         assertEquals(0, output.getNumBonds());
1347         assertEquals(0, output.getNumStereo0D());
1348         Assert
1349                 .assertEquals(
1350                         "InChI Atom: Cl [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE",
1351                         output.getAtom(0).getDebugString());
1352     }
1353 
1354     /**
1355      * Tests charge is correctly read from InChI.
1356      *
1357      * @throws Exception
1358      */
1359     @Test
1360     public void testGetChargeFromSodiumHydroxide() throws Exception {
1361 
1362         JniInchiInputInchi input = new JniInchiInputInchi("InChI=1S/Na.H2O/h;1H2/q+1;/p-1");
1363         JniInchiOutputStructure output = JniInchiWrapper.getStructureFromInchi(input);
1364         assertEquals(2, output.getNumAtoms());
1365         assertEquals(0, output.getNumBonds());
1366         assertEquals(0, output.getNumStereo0D());
1367         assertEquals("InChI Atom: Na [0.0,0.0,0.0] Charge:1 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE", output.getAtom(0).getDebugString());
1368         assertEquals("InChI Atom: O [0.0,0.0,0.0] Charge:-1 // Iso Mass:0 // Implicit H:1 P:0 D:0 T:0 // Radical: NONE", output.getAtom(1).getDebugString());
1369         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1370     }
1371 
1372     /**
1373      * Tests isotopic mass is correctly read from InChI.
1374      *
1375      * @throws Exception
1376      */
1377     @Test
1378     public void testGetChlorine37AtomFromInchi() throws Exception {
1379         JniInchiInputInchi input = new JniInchiInputInchi("InChI=1/Cl/i1+2");
1380         JniInchiOutputStructure output = JniInchiWrapper
1381                 .getStructureFromInchi(input);
1382         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1383         assertEquals(1, output.getNumAtoms());
1384         assertEquals(0, output.getNumBonds());
1385         assertEquals(0, output.getNumStereo0D());
1386         Assert
1387                 .assertEquals(
1388                         "InChI Atom: Cl [0.0,0.0,0.0] Charge:0 // Iso Mass:10002 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE",
1389                         output.getAtom(0).getDebugString());
1390     }
1391 
1392     /**
1393      * Tests implicit hydrogen count is correctly read from InChI.
1394      *
1395      * @throws Exception
1396      */
1397     @Test
1398     public void testGetHydrogenChlorideImplicitHFromInchi() throws Exception {
1399         JniInchiInputInchi input = new JniInchiInputInchi("InChI=1/ClH/h1H");
1400         JniInchiOutputStructure output = JniInchiWrapper
1401                 .getStructureFromInchi(input);
1402         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1403         assertEquals(1, output.getNumAtoms());
1404         assertEquals(0, output.getNumBonds());
1405         assertEquals(0, output.getNumStereo0D());
1406         Assert
1407                 .assertEquals(
1408                         "InChI Atom: Cl [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:1 P:0 D:0 T:0 // Radical: NONE",
1409                         output.getAtom(0).getDebugString());
1410     }
1411 
1412     /**
1413      * Tests implicit protium count is correctly read from InChI.
1414      *
1415      * @throws Exception
1416      */
1417     @Test
1418     public void testGetHydrogenChlorideImplicitPFromInchi() throws Exception {
1419         JniInchiInputInchi input = new JniInchiInputInchi(
1420                 "InChI=1/ClH/h1H/i/hH");
1421         JniInchiOutputStructure output = JniInchiWrapper
1422                 .getStructureFromInchi(input);
1423         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1424         assertEquals(1, output.getNumAtoms());
1425         assertEquals(0, output.getNumBonds());
1426         assertEquals(0, output.getNumStereo0D());
1427         Assert
1428                 .assertEquals(
1429                         "InChI Atom: Cl [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:1 D:0 T:0 // Radical: NONE",
1430                         output.getAtom(0).getDebugString());
1431     }
1432 
1433     /**
1434      * Tests implicit deuterium count is correctly read from InChi.
1435      *
1436      * @throws Exception
1437      */
1438     @Test
1439     public void testGetHydrogenChlorideImplicitDFromInchi() throws Exception {
1440         JniInchiInputInchi input = new JniInchiInputInchi(
1441                 "InChI=1/ClH/h1H/i/hD");
1442         JniInchiOutputStructure output = JniInchiWrapper
1443                 .getStructureFromInchi(input);
1444         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1445         assertEquals(1, output.getNumAtoms());
1446         assertEquals(0, output.getNumBonds());
1447         assertEquals(0, output.getNumStereo0D());
1448         Assert
1449                 .assertEquals(
1450                         "InChI Atom: Cl [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:1 T:0 // Radical: NONE",
1451                         output.getAtom(0).getDebugString());
1452     }
1453 
1454     /**
1455      * Tests implicit tritium count is correctly read from InChI.
1456      *
1457      * @throws Exception
1458      */
1459     @Test
1460     public void testGetHydrogenChlorideImplicitTFromInchi() throws Exception {
1461         JniInchiInputInchi input = new JniInchiInputInchi(
1462                 "InChI=1/ClH/h1H/i/hT");
1463         JniInchiOutputStructure output = JniInchiWrapper
1464                 .getStructureFromInchi(input);
1465         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1466         assertEquals(1, output.getNumAtoms());
1467         assertEquals(0, output.getNumBonds());
1468         assertEquals(0, output.getNumStereo0D());
1469         Assert
1470                 .assertEquals(
1471                         "InChI Atom: Cl [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:1 // Radical: NONE",
1472                         output.getAtom(0).getDebugString());
1473     }
1474 
1475     /**
1476      * Tests radical state is correctly read from InChI.
1477      *
1478      * @throws Exception
1479      */
1480     @Test
1481     @Ignore
1482     // Test fails due to problem with InChI library
1483     public void testGetMethylRadicalFromInchi() throws Exception {
1484 
1485         JniInchiInputInchi input = new JniInchiInputInchi("InChI=1/CH3/h1H3");
1486         JniInchiOutputStructure output = JniInchiWrapper.getStructureFromInchi(input);
1487         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1488         assertEquals(1, output.getNumAtoms());
1489         assertEquals(0, output.getNumBonds());
1490         assertEquals(0, output.getNumStereo0D());
1491         assertEquals("InChI Atom: C [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:3 P:0 D:0 T:0 // Radical: DOUBLET", output.getAtom(0).getDebugString());
1492     }
1493 
1494 
1495 
1496     // Test bond handling
1497 
1498     /**
1499      * Tests single bond is correctly read from InChI.
1500      *
1501      * @throws Exception
1502      */
1503     @Test
1504     public void testGetEthaneFromInchi() throws Exception {
1505         JniInchiInputInchi input = new JniInchiInputInchi(
1506                 "InChI=1/C2H6/c1-2/h1-2H3");
1507         JniInchiOutputStructure output = JniInchiWrapper
1508                 .getStructureFromInchi(input);
1509         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1510         assertEquals(2, output.getNumAtoms());
1511         assertEquals(1, output.getNumBonds());
1512         assertEquals(0, output.getNumStereo0D());
1513         Assert
1514                 .assertEquals(
1515                         "InChI Atom: C [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:3 P:0 D:0 T:0 // Radical: NONE",
1516                         output.getAtom(0).getDebugString());
1517         Assert
1518                 .assertEquals(
1519                         "InChI Atom: C [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:3 P:0 D:0 T:0 // Radical: NONE",
1520                         output.getAtom(1).getDebugString());
1521         assertEquals("InChI Bond: C-C // Type: SINGLE // Stereo: NONE",
1522                 output.getBond(0).getDebugString());
1523     }
1524 
1525     /**
1526      * Tests double bond is correctly read from InChI.
1527      *
1528      * @throws Exception
1529      */
1530     @Test
1531     public void testGetEtheneFromInchi() throws Exception {
1532         JniInchiInputInchi input = new JniInchiInputInchi(
1533                 "InChI=1/C2H4/c1-2/h1-2H2");
1534         JniInchiOutputStructure output = JniInchiWrapper
1535                 .getStructureFromInchi(input);
1536         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1537         assertEquals(2, output.getNumAtoms());
1538         assertEquals(1, output.getNumBonds());
1539         assertEquals(0, output.getNumStereo0D());
1540         Assert
1541                 .assertEquals(
1542                         "InChI Atom: C [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:2 P:0 D:0 T:0 // Radical: NONE",
1543                         output.getAtom(0).getDebugString());
1544         Assert
1545                 .assertEquals(
1546                         "InChI Atom: C [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:2 P:0 D:0 T:0 // Radical: NONE",
1547                         output.getAtom(1).getDebugString());
1548         assertEquals("InChI Bond: C-C // Type: DOUBLE // Stereo: NONE",
1549                 output.getBond(0).getDebugString());
1550     }
1551 
1552     /**
1553      * Tests triple bond is correctly read from InChI.
1554      *
1555      * @throws Exception
1556      */
1557     @Test
1558     public void testGetEthyneFromInchi() throws Exception {
1559         JniInchiInputInchi input = new JniInchiInputInchi(
1560                 "InChI=1/C2H2/c1-2/h1-2H");
1561         JniInchiOutputStructure output = JniInchiWrapper
1562                 .getStructureFromInchi(input);
1563         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1564         assertEquals(2, output.getNumAtoms());
1565         assertEquals(1, output.getNumBonds());
1566         assertEquals(0, output.getNumStereo0D());
1567         Assert
1568                 .assertEquals(
1569                         "InChI Atom: C [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:1 P:0 D:0 T:0 // Radical: NONE",
1570                         output.getAtom(0).getDebugString());
1571         Assert
1572                 .assertEquals(
1573                         "InChI Atom: C [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:1 P:0 D:0 T:0 // Radical: NONE",
1574                         output.getAtom(1).getDebugString());
1575         assertEquals("InChI Bond: C-C // Type: TRIPLE // Stereo: NONE",
1576                 output.getBond(0).getDebugString());
1577     }
1578 
1579     // Test handling of no coordinates, with stereo parities
1580 
1581     /**
1582      * Tests generation of L and D-Alanine molecules, from InChIs with
1583      * tetrahedral stereo parities.
1584      *
1585      * @throws Exception
1586      */
1587     @Test
1588     public void testGetLandDAlanine0DFromInchi() throws Exception {
1589         JniInchiInputInchi input = new JniInchiInputInchi(
1590                 "InChI=1/C3H7NO2/c1-2(4)3(5)6/h2H,4H2,1H3,(H,5,6)");
1591         JniInchiOutputStructure output = JniInchiWrapper
1592                 .getStructureFromInchi(input);
1593         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1594         assertEquals(6, output.getNumAtoms());
1595         assertEquals(5, output.getNumBonds());
1596         assertEquals(0, output.getNumStereo0D());
1597         Assert
1598                 .assertEquals(
1599                         "InChI Atom: C [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:3 P:0 D:0 T:0 // Radical: NONE",
1600                         output.getAtom(0).getDebugString());
1601         Assert
1602                 .assertEquals(
1603                         "InChI Atom: C [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:1 P:0 D:0 T:0 // Radical: NONE",
1604                         output.getAtom(1).getDebugString());
1605         Assert
1606                 .assertEquals(
1607                         "InChI Atom: C [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE",
1608                         output.getAtom(2).getDebugString());
1609         Assert
1610                 .assertEquals(
1611                         "InChI Atom: N [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:2 P:0 D:0 T:0 // Radical: NONE",
1612                         output.getAtom(3).getDebugString());
1613         Assert
1614                 .assertEquals(
1615                         "InChI Atom: O [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE",
1616                         output.getAtom(4).getDebugString());
1617         Assert
1618                 .assertEquals(
1619                         "InChI Atom: O [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:1 P:0 D:0 T:0 // Radical: NONE",
1620                         output.getAtom(5).getDebugString());
1621         assertEquals("InChI Bond: C-C // Type: SINGLE // Stereo: NONE",
1622                 output.getBond(0).getDebugString());
1623         assertEquals("InChI Bond: C-C // Type: SINGLE // Stereo: NONE",
1624                 output.getBond(1).getDebugString());
1625         assertEquals("InChI Bond: N-C // Type: SINGLE // Stereo: NONE",
1626                 output.getBond(2).getDebugString());
1627         assertEquals("InChI Bond: O-C // Type: DOUBLE // Stereo: NONE",
1628                 output.getBond(3).getDebugString());
1629         assertEquals("InChI Bond: O-C // Type: SINGLE // Stereo: NONE",
1630                 output.getBond(4).getDebugString());
1631 
1632         JniInchiInputInchi inputL = new JniInchiInputInchi(
1633                 "InChI=1/C3H7NO2/c1-2(4)3(5)6/h2H,4H2,1H3,(H,5,6)/t2-/m0/s1");
1634         JniInchiOutputStructure outputL = JniInchiWrapper
1635                 .getStructureFromInchi(inputL);
1636         assertEquals(INCHI_RET.OKAY, outputL.getReturnStatus());
1637         assertEquals(7, outputL.getNumAtoms());
1638         assertEquals(6, outputL.getNumBonds());
1639         assertEquals(1, outputL.getNumStereo0D());
1640         Assert
1641                 .assertEquals(
1642                         "InChI Atom: C [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:3 P:0 D:0 T:0 // Radical: NONE",
1643                         outputL.getAtom(0).getDebugString());
1644         Assert
1645                 .assertEquals(
1646                         "InChI Atom: C [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE",
1647                         outputL.getAtom(1).getDebugString());
1648         Assert
1649                 .assertEquals(
1650                         "InChI Atom: C [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE",
1651                         outputL.getAtom(2).getDebugString());
1652         Assert
1653                 .assertEquals(
1654                         "InChI Atom: N [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:2 P:0 D:0 T:0 // Radical: NONE",
1655                         outputL.getAtom(3).getDebugString());
1656         Assert
1657                 .assertEquals(
1658                         "InChI Atom: O [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE",
1659                         outputL.getAtom(4).getDebugString());
1660         Assert
1661                 .assertEquals(
1662                         "InChI Atom: O [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:1 P:0 D:0 T:0 // Radical: NONE",
1663                         outputL.getAtom(5).getDebugString());
1664         assertEquals("InChI Bond: C-C // Type: SINGLE // Stereo: NONE",
1665                 outputL.getBond(0).getDebugString());
1666         assertEquals("InChI Bond: C-C // Type: SINGLE // Stereo: NONE",
1667                 outputL.getBond(1).getDebugString());
1668         assertEquals("InChI Bond: N-C // Type: SINGLE // Stereo: NONE",
1669                 outputL.getBond(2).getDebugString());
1670         assertEquals("InChI Bond: O-C // Type: DOUBLE // Stereo: NONE",
1671                 outputL.getBond(3).getDebugString());
1672         assertEquals("InChI Bond: O-C // Type: SINGLE // Stereo: NONE",
1673                 outputL.getBond(4).getDebugString());
1674         assertEquals(
1675                 "InChI Stereo0D: C [H,C,C,N] Type::TETRAHEDRAL // Parity:ODD",
1676                 outputL.getStereo0D(0).getDebugString());
1677 
1678         JniInchiInputInchi inputD = new JniInchiInputInchi(
1679                 "InChI=1/C3H7NO2/c1-2(4)3(5)6/h2H,4H2,1H3,(H,5,6)/t2-/m1/s1");
1680         JniInchiOutputStructure outputD = JniInchiWrapper
1681                 .getStructureFromInchi(inputD);
1682         assertEquals(INCHI_RET.OKAY, outputD.getReturnStatus());
1683         assertEquals(7, outputD.getNumAtoms());
1684         assertEquals(6, outputD.getNumBonds());
1685         assertEquals(1, outputD.getNumStereo0D());
1686         Assert
1687                 .assertEquals(
1688                         "InChI Atom: C [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:3 P:0 D:0 T:0 // Radical: NONE",
1689                         outputD.getAtom(0).getDebugString());
1690         Assert
1691                 .assertEquals(
1692                         "InChI Atom: C [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE",
1693                         outputD.getAtom(1).getDebugString());
1694         Assert
1695                 .assertEquals(
1696                         "InChI Atom: C [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE",
1697                         outputD.getAtom(2).getDebugString());
1698         Assert
1699                 .assertEquals(
1700                         "InChI Atom: N [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:2 P:0 D:0 T:0 // Radical: NONE",
1701                         outputD.getAtom(3).getDebugString());
1702         Assert
1703                 .assertEquals(
1704                         "InChI Atom: O [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE",
1705                         outputD.getAtom(4).getDebugString());
1706         Assert
1707                 .assertEquals(
1708                         "InChI Atom: O [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:1 P:0 D:0 T:0 // Radical: NONE",
1709                         outputD.getAtom(5).getDebugString());
1710         assertEquals("InChI Bond: C-C // Type: SINGLE // Stereo: NONE",
1711                 outputD.getBond(0).getDebugString());
1712         assertEquals("InChI Bond: C-C // Type: SINGLE // Stereo: NONE",
1713                 outputD.getBond(1).getDebugString());
1714         assertEquals("InChI Bond: N-C // Type: SINGLE // Stereo: NONE",
1715                 outputD.getBond(2).getDebugString());
1716         assertEquals("InChI Bond: O-C // Type: DOUBLE // Stereo: NONE",
1717                 outputD.getBond(3).getDebugString());
1718         assertEquals("InChI Bond: O-C // Type: SINGLE // Stereo: NONE",
1719                 outputD.getBond(4).getDebugString());
1720         assertEquals(
1721                 "InChI Stereo0D: C [H,C,C,N] Type::TETRAHEDRAL // Parity:EVEN",
1722                 outputD.getStereo0D(0).getDebugString());
1723     };
1724 
1725     /**
1726      * Tests generation of E and Z 1,2-dichloroethene molecules, from InChIs
1727      * with doublebond stereo parities.
1728      *
1729      * @throws Exception
1730      */
1731     @Test
1732     public void testGetEandZ12Dichloroethene0DFromInchi() throws Exception {
1733         JniInchiInputInchi input = new JniInchiInputInchi(
1734                 "InChI=1/C2H2Cl2/c3-1-2-4/h1-2H");
1735         JniInchiOutputStructure output = JniInchiWrapper
1736                 .getStructureFromInchi(input);
1737         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1738         assertEquals(4, output.getNumAtoms());
1739         assertEquals(3, output.getNumBonds());
1740         assertEquals(0, output.getNumStereo0D());
1741         Assert
1742                 .assertEquals(
1743                         "InChI Atom: C [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:1 P:0 D:0 T:0 // Radical: NONE",
1744                         output.getAtom(0).getDebugString());
1745         Assert
1746                 .assertEquals(
1747                         "InChI Atom: C [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:1 P:0 D:0 T:0 // Radical: NONE",
1748                         output.getAtom(1).getDebugString());
1749         Assert
1750                 .assertEquals(
1751                         "InChI Atom: Cl [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE",
1752                         output.getAtom(2).getDebugString());
1753         Assert
1754                 .assertEquals(
1755                         "InChI Atom: Cl [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE",
1756                         output.getAtom(3).getDebugString());
1757         assertEquals("InChI Bond: C-C // Type: DOUBLE // Stereo: NONE",
1758                 output.getBond(0).getDebugString());
1759         assertEquals("InChI Bond: Cl-C // Type: SINGLE // Stereo: NONE",
1760                 output.getBond(1).getDebugString());
1761         assertEquals("InChI Bond: Cl-C // Type: SINGLE // Stereo: NONE",
1762                 output.getBond(2).getDebugString());
1763 
1764         JniInchiInputInchi inputE = new JniInchiInputInchi(
1765                 "InChI=1/C2H2Cl2/c3-1-2-4/h1-2H/b2-1+");
1766         JniInchiOutputStructure outputE = JniInchiWrapper
1767                 .getStructureFromInchi(inputE);
1768         assertEquals(INCHI_RET.OKAY, outputE.getReturnStatus());
1769         assertEquals(6, outputE.getNumAtoms());
1770         assertEquals(5, outputE.getNumBonds());
1771         assertEquals(1, outputE.getNumStereo0D());
1772         Assert
1773                 .assertEquals(
1774                         "InChI Atom: C [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE",
1775                         outputE.getAtom(0).getDebugString());
1776         Assert
1777                 .assertEquals(
1778                         "InChI Atom: C [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE",
1779                         outputE.getAtom(1).getDebugString());
1780         Assert
1781                 .assertEquals(
1782                         "InChI Atom: Cl [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE",
1783                         outputE.getAtom(2).getDebugString());
1784         Assert
1785                 .assertEquals(
1786                         "InChI Atom: Cl [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE",
1787                         outputE.getAtom(3).getDebugString());
1788         Assert
1789                 .assertEquals(
1790                         "InChI Atom: H [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE",
1791                         outputE.getAtom(4).getDebugString());
1792         Assert
1793                 .assertEquals(
1794                         "InChI Atom: H [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE",
1795                         outputE.getAtom(5).getDebugString());
1796         assertEquals("InChI Bond: C-C // Type: DOUBLE // Stereo: NONE",
1797                 outputE.getBond(0).getDebugString());
1798         assertEquals("InChI Bond: Cl-C // Type: SINGLE // Stereo: NONE",
1799                 outputE.getBond(1).getDebugString());
1800         assertEquals("InChI Bond: Cl-C // Type: SINGLE // Stereo: NONE",
1801                 outputE.getBond(2).getDebugString());
1802         assertEquals(
1803                 "InChI Stereo0D: - [H,C,C,H] Type::DOUBLEBOND // Parity:EVEN",
1804                 outputE.getStereo0D(0).getDebugString());
1805 
1806         JniInchiInputInchi inputZ = new JniInchiInputInchi(
1807                 "InChI=1/C2H2Cl2/c3-1-2-4/h1-2H/b2-1-");
1808         JniInchiOutputStructure outputZ = JniInchiWrapper
1809                 .getStructureFromInchi(inputZ);
1810         assertEquals(INCHI_RET.OKAY, outputZ.getReturnStatus());
1811         assertEquals(6, outputZ.getNumAtoms());
1812         assertEquals(5, outputZ.getNumBonds());
1813         assertEquals(1, outputZ.getNumStereo0D());
1814         Assert
1815                 .assertEquals(
1816                         "InChI Atom: C [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE",
1817                         outputZ.getAtom(0).getDebugString());
1818         Assert
1819                 .assertEquals(
1820                         "InChI Atom: C [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE",
1821                         outputZ.getAtom(1).getDebugString());
1822         Assert
1823                 .assertEquals(
1824                         "InChI Atom: Cl [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE",
1825                         outputZ.getAtom(2).getDebugString());
1826         Assert
1827                 .assertEquals(
1828                         "InChI Atom: Cl [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE",
1829                         outputZ.getAtom(3).getDebugString());
1830         Assert
1831                 .assertEquals(
1832                         "InChI Atom: H [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE",
1833                         outputZ.getAtom(4).getDebugString());
1834         Assert
1835                 .assertEquals(
1836                         "InChI Atom: H [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:0 P:0 D:0 T:0 // Radical: NONE",
1837                         outputZ.getAtom(5).getDebugString());
1838         assertEquals("InChI Bond: C-C // Type: DOUBLE // Stereo: NONE",
1839                 outputZ.getBond(0).getDebugString());
1840         assertEquals("InChI Bond: Cl-C // Type: SINGLE // Stereo: NONE",
1841                 outputZ.getBond(1).getDebugString());
1842         assertEquals("InChI Bond: Cl-C // Type: SINGLE // Stereo: NONE",
1843                 outputZ.getBond(2).getDebugString());
1844         assertEquals(
1845                 "InChI Stereo0D: - [H,C,C,H] Type::DOUBLEBOND // Parity:ODD",
1846                 outputZ.getStereo0D(0).getDebugString());
1847     };
1848 
1849 
1850     /**
1851      * Tests InchiKey generation.
1852      * @throws JniInchiException
1853      */
1854     @Test
1855     public void testGetInchiKeyForCafeine() throws JniInchiException {
1856         String inchi = "InChI=1/C8H10N4O2/c1-10-4-9-6-5(10)7(13)12(3)8(14)11(6)2/h4H,1-3H3";
1857         JniInchiOutputKey output = JniInchiWrapper.getInchiKey(inchi);
1858         assertEquals(INCHI_KEY.OK, output.getReturnStatus());
1859         assertEquals("RYYVLZVUVIJVGH-UHFFFAOYNA-N", output.getKey());
1860     }
1861 
1862     /**
1863      * Tests InchiKey generation.
1864      * @throws JniInchiException
1865      */
1866     @Test
1867     public void testGetStdInchiKeyForCafeine() throws JniInchiException {
1868         String inchi = "InChI=1S/C8H10N4O2/c1-10-4-9-6-5(10)7(13)12(3)8(14)11(6)2/h4H,1-3H3";
1869         JniInchiOutputKey output = JniInchiWrapper.getInchiKey(inchi);
1870         assertEquals(INCHI_KEY.OK, output.getReturnStatus());
1871         assertEquals("RYYVLZVUVIJVGH-UHFFFAOYSA-N", output.getKey());
1872     }
1873 
1874     @Test
1875     public void testGetInchiKeyEmptyInput() throws JniInchiException {
1876         String inchi = "";
1877         JniInchiOutputKey output = JniInchiWrapper.getInchiKey(inchi);
1878         assertEquals(INCHI_KEY.INVALID_INCHI_PREFIX, output.getReturnStatus());
1879     }
1880 
1881     @Test
1882     public void testGetInchiKeyInputInvalidPrefix() throws JniInchiException {
1883         String inchi = "foo=1/C8H10N4O2/c1-10-4-9-6-5(10)7(13)12(3)8(14)11(6)2/h4H,1-3H3";
1884         JniInchiOutputKey output = JniInchiWrapper.getInchiKey(inchi);
1885         assertEquals(INCHI_KEY.INVALID_INCHI_PREFIX, output.getReturnStatus());
1886     }
1887 
1888     @Test
1889     public void testGetInchiKeyInputInvalidInchi() throws JniInchiException {
1890         String inchi = "InChI=1/-";
1891         JniInchiOutputKey output = JniInchiWrapper.getInchiKey(inchi);
1892         assertEquals(INCHI_KEY.INVALID_INCHI, output.getReturnStatus());
1893     }
1894 
1895     @Test
1896     @Ignore
1897     // InChI library does very little checking of input,
1898     // many invalid InChIs will produce InChI keys...
1899     public void testGetInchiKeyInputInvalidInchi1() throws JniInchiException {
1900         String inchi = "InChI=1/C8H10N4O2/x1-9-4-9-6-5(10)7(13)12(3)8(14)11(6)2/h4H,1-3H3";
1901         JniInchiOutputKey output = JniInchiWrapper.getInchiKey(inchi);
1902         assertEquals(INCHI_KEY.INVALID_INCHI, output.getReturnStatus());
1903     }
1904 
1905     @Test
1906     public void testCheckInchiKeyValid() throws JniInchiException {
1907         String key = "RYYVLZVUVIJVGH-UHFFFAOYNA-N";
1908         INCHI_KEY_STATUS status = JniInchiWrapper.checkInchiKey(key);
1909         assertEquals(INCHI_KEY_STATUS.VALID_NON_STANDARD, status);
1910     }
1911 
1912     @Test
1913     public void testCheckInchiKeyInvalidLengthLong() throws JniInchiException {
1914         String key = "RYYVLZVUVIJVGH-UHFFFAOYNA-NX";
1915         INCHI_KEY_STATUS status1 = JniInchiWrapper.checkInchiKey(key);
1916         assertEquals(INCHI_KEY_STATUS.INVALID_LENGTH, status1);
1917     }
1918 
1919     @Test
1920     public void testCheckInchiKeyInvalidLengthShort() throws JniInchiException {
1921         String key = "RYYVLZVUVIJVGH-UHFFFAOYNA-";
1922         INCHI_KEY_STATUS status2 = JniInchiWrapper.checkInchiKey(key);
1923         assertEquals(INCHI_KEY_STATUS.INVALID_LENGTH, status2);
1924     }
1925 
1926     @Test
1927     public void testCheckInchiKeyInvalidLayout() throws JniInchiException {
1928         String key = "RYYVLZVUVIJVGHXUHFFFAOYNAXN";
1929         INCHI_KEY_STATUS status = JniInchiWrapper.checkInchiKey(key);
1930         assertEquals(INCHI_KEY_STATUS.INVALID_LAYOUT, status);
1931     }
1932 
1933     @Test
1934     public void testCheckInchiKeyInvalidVersion() throws JniInchiException {
1935         String key = "RYYVLZVUVIJVGH-UHFFFAOYNX-N";
1936         INCHI_KEY_STATUS status = JniInchiWrapper.checkInchiKey(key);
1937         assertEquals(INCHI_KEY_STATUS.INVALID_VERSION, status);
1938     }
1939 
1940     /* Option doesn't work yet
1941     @Test
1942     @Ignore
1943     public void testGenerateInchiKeyViaOptions() throws JniInchiException {
1944         JniInchiInput input = getLAlanine3D("-key");
1945         JniInchiOutput output = JniInchiWrapper.getInchi(input);
1946         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
1947 //        assertEquals(null, output.getInchi());
1948 //        assertEquals(null, output.getAuxInfo());
1949 //        assertEquals(null, output.getMessage());
1950 //        assertEquals(null, output.getLog());
1951     }
1952     */
1953 
1954 
1955     /**
1956      * Tests thread safety - starts ten threads, and sets them generating InChIs
1957      * for randomly picked elements. Checks generated InChIs are as expected.
1958      *
1959      */
1960     @Test
1961     public void multithreading() {
1962 
1963         // Start threads
1964         int nthreads = 5;
1965         TestThread[] threads = new TestThread[nthreads];
1966         for (int i = 0; i < nthreads; i++) {
1967             threads[i] = new TestThread(i);
1968             threads[i].start();
1969             Thread.yield();
1970         }
1971 
1972         // Wait for threads to get going
1973         try {
1974             Thread.sleep(500);
1975         } catch (InterruptedException ie) {
1976             fail("Interrupted");
1977         }
1978 
1979         boolean allRunning = true;
1980 
1981         // Stop threads
1982         for (int i = 0; i < nthreads; i++) {
1983             if (threads[i].runCount < 1) {
1984                 allRunning = false;
1985             }
1986             threads[i].finish();
1987             Thread.yield();
1988         }
1989 
1990         assertTrue("All threads running", allRunning);
1991 
1992         // Wait for threads to stop
1993         long tstop = System.currentTimeMillis() + 30000;
1994         try {
1995             for (int i = 0; i < nthreads; i++) {
1996                 long t0 = System.currentTimeMillis();
1997                 threads[i].join(Math.max(1,tstop-t0));
1998             }
1999         } catch (InterruptedException ie) {
2000             fail("Interrupted");
2001         }
2002 
2003         // Check threads have finished
2004         boolean allFinished = true;
2005         for (int i = 0; i < nthreads; i++) {
2006             if (!threads[i].isDone()) {
2007                 allFinished = false;
2008                 break;
2009             }
2010         }
2011         assertTrue("All finished", allFinished);
2012 
2013         int failureCount = 0;
2014         for (int i = 0; i < nthreads; i++) {
2015             failureCount += threads[i].failCount;
2016         }
2017 
2018         assertEquals("Fail count", 0, failureCount);
2019     }
2020 
2021 
2022     @Test
2023     public void testTooManyAtoms() throws JniInchiException {
2024         JniInchiInput input = new JniInchiInput();
2025         for (int i = 0; i < 2000; i++) {
2026             input.addAtom(new JniInchiAtom(0, 0, 0, "C"));
2027         }
2028         try {
2029             JniInchiWrapper.getInchi(input);
2030             fail("too many atoms");
2031         } catch (IllegalArgumentException e) {
2032             ; // pass
2033         }
2034     }
2035 
2036 
2037 
2038 
2039     @Test
2040     public void testStructureToInchiBug2085031a() throws Exception {
2041         JniInchiInputInchi input = new JniInchiInputInchi(
2042                 "InChI=1/C24H33N3O5/c1-23(2,3)26-21(29)20(17-11-8-7-9-12-17)27(16-18-13-10-14-31-18)19(28)15-25-22(30)32-24(4,5)6/h7-14,20H,15-16H2,1-6H3,(H,25,30)(H,26,29)");
2043         JniInchiOutputStructure output = JniInchiWrapper
2044                 .getStructureFromInchi(input);
2045         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
2046     }
2047 
2048     @Test
2049     public void testStructureToInchiBug2085031b() throws Exception {
2050         JniInchiInputInchi input = new JniInchiInputInchi(
2051                 "InChI=1/C24H33N3O5/c1-23(2,3)26-21(29)20(17-11-8-7-9-12-17)27(16-18-13-10-14-31-18)19(28)15-25-22(30)32-24(4,5)6/h7-14,20H,15-16H2,1-6H3,(H,25,30)(H,26,29) ");
2052         JniInchiOutputStructure output = JniInchiWrapper
2053                 .getStructureFromInchi(input);
2054         assertEquals(INCHI_RET.EOF, output.getReturnStatus());
2055     }
2056 
2057 
2058 
2059 
2060     private class TestThread extends Thread {
2061 
2062         private String[] ELS = { "H", "He", "Li", "Be", "B", "C", "N", "O",
2063                 "F", "Ne", "Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar" };
2064 
2065         private volatile boolean stop = false;
2066         private volatile boolean done = false;
2067 
2068         public volatile int failCount = 0;
2069         public volatile int runCount = 0;
2070 
2071         public Exception ex;
2072 
2073         public final int threadIndex;
2074 
2075         public TestThread(final int i) {
2076             this.threadIndex = i;
2077         }
2078 
2079         public void run() {
2080 //            System.err.println("Thread "+threadIndex+" starting");
2081             Random rand = new Random();
2082             while (!stop) {
2083                 yield();
2084                 runCount++;
2085                 JniInchiInput input = new JniInchiInput();
2086                 String element = ELS[rand.nextInt(ELS.length)];
2087                 input.addAtom(new JniInchiAtom(0, 0, 0, element));
2088                 input.getAtom(0).setImplicitH(0);
2089                 try {
2090                     JniInchiOutput output = JniInchiWrapper.getInchi(input);
2091                     if (INCHI_RET.OKAY != output.getReturnStatus()) {
2092                         failCount++;
2093                     } else if (!("InChI=1S/" + element)
2094                             .equals(output.getInchi())) {
2095                         failCount++;
2096                     }
2097                 } catch (Exception e) {
2098                     failCount++;
2099                     ex = e;
2100                     System.err.println("Thread "+threadIndex+ " error: " + e.getMessage());
2101                     break;
2102                 }
2103                 yield();
2104             }
2105             done = true;
2106 //            System.err.println("Thread "+threadIndex+" stopping");
2107         }
2108 
2109         public void finish() {
2110             this.stop = true;
2111         }
2112 
2113         public boolean isDone() {
2114             return done;
2115         }
2116 
2117     }
2118 
2119 
2120 
2121     @Test
2122     public void testGetStdInchi() throws JniInchiException {
2123         JniInchiInput input = getLAlanine0D("");
2124         JniInchiOutput output = JniInchiWrapper.getStdInchi(input);
2125         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
2126         assertEquals(
2127                 "InChI=1S/C3H7NO2/c1-2(4)3(5)6/h2H,4H2,1H3,(H,5,6)/t2-/m0/s1",
2128                 output.getInchi());
2129     }
2130 
2131 
2132     // Test null inputs
2133 
2134     @Test(expected = IllegalArgumentException.class)
2135     public void testCheckInchiKeyNull() throws JniInchiException {
2136         JniInchiWrapper.checkInchiKey(null);
2137     }
2138 
2139     @Test(expected = IllegalArgumentException.class)
2140     public void testCheckOptionsListNull() throws JniInchiException {
2141         JniInchiWrapper.checkOptions((List)null);
2142     }
2143 
2144     @Test(expected = IllegalArgumentException.class)
2145     public void testCheckOptionsStringNull() throws JniInchiException {
2146         JniInchiWrapper.checkOptions((String)null);
2147     }
2148 
2149     @Test(expected = IllegalArgumentException.class)
2150     public void testGetInchiNull() throws JniInchiException {
2151         JniInchiWrapper.getInchi(null);
2152     }
2153 
2154     @Test(expected = IllegalArgumentException.class)
2155     public void testGetInchiFromInchiNull() throws JniInchiException {
2156         JniInchiWrapper.getInchiFromInchi(null);
2157     }
2158 
2159     @Test(expected = IllegalArgumentException.class)
2160     public void testGetInchiKeyNull() throws JniInchiException {
2161         JniInchiWrapper.getInchiKey(null);
2162     }
2163 
2164     @Test(expected = IllegalArgumentException.class)
2165     public void testGetStdInchiNull() throws JniInchiException {
2166         JniInchiWrapper.getStdInchi(null);
2167     }
2168 
2169     @Test(expected = IllegalArgumentException.class)
2170     public void testGetStructureFromInchiNull() throws JniInchiException {
2171         JniInchiWrapper.getStructureFromInchi(null);
2172     }
2173 
2174     @Test
2175     public void testGetInputFromAuxInfoLAlanine3D() throws JniInchiException {
2176         JniInchiInputData data = JniInchiWrapper.getInputFromAuxInfo("AuxInfo=1/1/N:4,1,2,3,5,6/E:(5,6)/it:im/rA:6CCNCOO/rB:s1;s1;s1;s2;d2;/rC:-.358,.819,20.655;-1.598,-.032,20.905;-.275,2.014,21.574;.952,.043,20.838;-2.678,.479,21.093;-1.596,-1.239,20.958;");
2177         assertEquals(INCHI_RET.OKAY, data.getReturnValue());
2178         JniInchiInput input = data.getInput();
2179         assertEquals(6, input.getNumAtoms());
2180         assertEquals("InChI Atom: C [-0.358,0.819,20.655] Charge:0 // Iso Mass:0 // Implicit H:-1 P:0 D:0 T:0 // Radical: NONE", input.getAtom(0).getDebugString());
2181         assertEquals("InChI Atom: C [-1.598,-0.032,20.905] Charge:0 // Iso Mass:0 // Implicit H:-1 P:0 D:0 T:0 // Radical: NONE", input.getAtom(1).getDebugString());
2182         assertEquals("InChI Atom: N [-0.275,2.014,21.574] Charge:0 // Iso Mass:0 // Implicit H:-1 P:0 D:0 T:0 // Radical: NONE", input.getAtom(2).getDebugString());
2183         assertEquals("InChI Atom: C [0.952,0.043,20.838] Charge:0 // Iso Mass:0 // Implicit H:-1 P:0 D:0 T:0 // Radical: NONE", input.getAtom(3).getDebugString());
2184         assertEquals("InChI Atom: O [-2.678,0.479,21.093] Charge:0 // Iso Mass:0 // Implicit H:-1 P:0 D:0 T:0 // Radical: NONE", input.getAtom(4).getDebugString());
2185         assertEquals("InChI Atom: O [-1.596,-1.239,20.958] Charge:0 // Iso Mass:0 // Implicit H:-1 P:0 D:0 T:0 // Radical: NONE", input.getAtom(5).getDebugString());
2186         assertEquals(5, input.getNumBonds());
2187         assertEquals("InChI Bond: C-C // Type: SINGLE // Stereo: NONE", input.getBond(0).getDebugString());
2188         assertEquals("InChI Bond: N-C // Type: SINGLE // Stereo: NONE", input.getBond(1).getDebugString());
2189         assertEquals("InChI Bond: C-C // Type: SINGLE // Stereo: NONE", input.getBond(2).getDebugString());
2190         assertEquals("InChI Bond: O-C // Type: SINGLE // Stereo: NONE", input.getBond(3).getDebugString());
2191         assertEquals("InChI Bond: O-C // Type: DOUBLE // Stereo: NONE", input.getBond(4).getDebugString());
2192         assertEquals(0, input.getNumStereo0D());
2193     }
2194 
2195 
2196     @Test
2197     public void testGetInputFromAuxInfoE12DiChloroEthane() throws JniInchiException {
2198         JniInchiInputData data = JniInchiWrapper.getInputFromAuxInfo("AuxInfo=1/0/N:1,2,3,4/E:(1,2)(3,4)/rA:4CCClCl/rB:d+1;s1;s2;/rC:;;;;");
2199         assertEquals(INCHI_RET.OKAY, data.getReturnValue());
2200         JniInchiInput input = data.getInput();
2201         assertEquals(4, input.getNumAtoms());
2202         assertEquals("InChI Atom: C [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:-1 P:0 D:0 T:0 // Radical: NONE", input.getAtom(0).getDebugString());
2203         assertEquals("InChI Atom: C [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:-1 P:0 D:0 T:0 // Radical: NONE", input.getAtom(1).getDebugString());
2204         assertEquals("InChI Atom: Cl [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:-1 P:0 D:0 T:0 // Radical: NONE", input.getAtom(2).getDebugString());
2205         assertEquals("InChI Atom: Cl [0.0,0.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:-1 P:0 D:0 T:0 // Radical: NONE", input.getAtom(3).getDebugString());
2206         assertEquals(3, input.getNumBonds());
2207         assertEquals("InChI Bond: C-C // Type: DOUBLE // Stereo: NONE", input.getBond(0).getDebugString());
2208         assertEquals("InChI Bond: Cl-C // Type: SINGLE // Stereo: NONE", input.getBond(1).getDebugString());
2209         assertEquals("InChI Bond: Cl-C // Type: SINGLE // Stereo: NONE", input.getBond(2).getDebugString());
2210         assertEquals(1, input.getNumStereo0D());
2211         assertEquals("InChI Stereo0D: - [Cl,C,C,Cl] Type::DOUBLEBOND // Parity:EVEN", input.getStereo0D(0).getDebugString());
2212     }
2213 
2214     @Test
2215     public void testGetInputFromLAlanine2D() throws JniInchiException {
2216         JniInchiInputData data = JniInchiWrapper.getInputFromAuxInfo("AuxInfo=1/1/N:4,1,2,3,5,6/E:(5,6)/it:im/rA:6CCNCOO/rB:s1;N1;s1;s2;d2;/rC:264,968,0;295,985,0;233,986,0;264,932,0;326,967,0;295,1021,0;");
2217         assertEquals(INCHI_RET.OKAY, data.getReturnValue());
2218         JniInchiInput input = data.getInput();
2219         assertEquals(6, input.getNumAtoms());
2220         assertEquals("InChI Atom: C [264.0,968.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:-1 P:0 D:0 T:0 // Radical: NONE", input.getAtom(0).getDebugString());
2221         assertEquals("InChI Atom: C [295.0,985.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:-1 P:0 D:0 T:0 // Radical: NONE", input.getAtom(1).getDebugString());
2222         assertEquals("InChI Atom: N [233.0,986.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:-1 P:0 D:0 T:0 // Radical: NONE", input.getAtom(2).getDebugString());
2223         assertEquals("InChI Atom: C [264.0,932.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:-1 P:0 D:0 T:0 // Radical: NONE", input.getAtom(3).getDebugString());
2224         assertEquals("InChI Atom: O [326.0,967.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:-1 P:0 D:0 T:0 // Radical: NONE", input.getAtom(4).getDebugString());
2225         assertEquals("InChI Atom: O [295.0,1021.0,0.0] Charge:0 // Iso Mass:0 // Implicit H:-1 P:0 D:0 T:0 // Radical: NONE", input.getAtom(5).getDebugString());
2226         assertEquals(5, input.getNumBonds());
2227         assertEquals("InChI Bond: C-C // Type: SINGLE // Stereo: NONE", input.getBond(0).getDebugString());
2228         assertEquals("InChI Bond: N-C // Type: SINGLE // Stereo: SINGLE_2DOWN", input.getBond(1).getDebugString());
2229         assertEquals("InChI Bond: C-C // Type: SINGLE // Stereo: NONE", input.getBond(2).getDebugString());
2230         assertEquals("InChI Bond: O-C // Type: SINGLE // Stereo: NONE", input.getBond(3).getDebugString());
2231         assertEquals("InChI Bond: O-C // Type: DOUBLE // Stereo: NONE", input.getBond(4).getDebugString());
2232         assertEquals(0, input.getNumStereo0D());
2233     }
2234 
2235 
2236     @Test
2237     public void testCheckInchiValidStd() throws JniInchiException {
2238         String inchi = "InChI=1S/C3H7NO2/c1-2(4)3(5)6/h2H,4H2,1H3,(H,5,6)/t2-/m0/s1";
2239         INCHI_STATUS ret = JniInchiWrapper.checkInchi(inchi, false);
2240         assertEquals(INCHI_STATUS.VALID_STANDARD, ret);
2241     }
2242 
2243     @Test
2244     @Ignore     // TODO -- this seems to be an InChI bug
2245     public void testCheckInchiValidStdStrict() throws JniInchiException {
2246         String inchi = "InChI=1S/C4H6/c1-3-4-2/h3-4H,1-2H2";
2247         INCHI_STATUS ret = JniInchiWrapper.checkInchi(inchi, true);
2248         assertEquals(INCHI_STATUS.VALID_STANDARD, ret);
2249     }
2250 
2251     @Test
2252     public void testCheckInchiValidNonStd() throws JniInchiException {
2253         String inchi = "InChI=1/C8H10N4O2/c1-10-4-9-6-5(10)7(13)12(3)8(14)11(6)2/h4H,1-3H3";
2254         INCHI_STATUS ret = JniInchiWrapper.checkInchi(inchi, false);
2255         assertEquals(INCHI_STATUS.VALID_NON_STANDARD, ret);
2256     }
2257 
2258     @Test
2259     public void testCheckInchiInvalidVersion() throws JniInchiException {
2260         String inchi = "InChI=2/C8H10N4O2/c1-10-4-9-6-5(10)7(13)12(3)8(14)11(6)2/h4H,1-3H3";
2261         INCHI_STATUS ret = JniInchiWrapper.checkInchi(inchi, false);
2262         assertEquals(INCHI_STATUS.INVALID_VERSION, ret);
2263     }
2264 
2265     @Test
2266     public void testCheckInchiInvalidPrefix() throws JniInchiException {
2267         String inchi = "foo=1/C8H10N4O2/c1-10-4-9-6-5(10)7(13)12(3)8(14)11(6)2/h4H,1-3H3";
2268         INCHI_STATUS ret = JniInchiWrapper.checkInchi(inchi, false);
2269         assertEquals(INCHI_STATUS.INVALID_PREFIX, ret);
2270     }
2271 
2272 
2273     @Test
2274     public void testGetInchiFromInchi() throws JniInchiException {
2275         String inchi = "InChI=1S/C4H6/c1-3-4-2/h3-4H,1-2H2";
2276         JniInchiInputInchi input = new JniInchiInputInchi(inchi);
2277         JniInchiOutput output = JniInchiWrapper.getInchiFromInchi(input);
2278         assertEquals(INCHI_RET.OKAY, output.getReturnStatus());
2279         assertEquals(inchi, output.getInchi());
2280     }
2281 }