1 /* 2 * Copyright (c) 2018 John Mayfield <jwmay@users.sf.net> 3 * 4 * Contact: cdk-devel@lists.sourceforge.net 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU Lesser General Public License as published by 8 * the Free Software Foundation; either version 2.1 of the License, or (at 9 * your option) any later version. All we ask is that proper credit is given 10 * for our work, which includes - but is not limited to - adding the above 11 * copyright notice to the beginning of your source code files, and to any 12 * copyright notice that you may distribute with programs based on this work. 13 * 14 * This program is distributed in the hope that it will be useful, but WITHOUT 15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 17 * License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 */ 23 24 package org.openscience.cdk.smarts; 25 26 import org.junit.Test; 27 import org.openscience.cdk.AtomRef; 28 import org.openscience.cdk.BondRef; 29 import org.openscience.cdk.CDKConstants; 30 import org.openscience.cdk.config.Elements; 31 import org.openscience.cdk.interfaces.IAtom; 32 import org.openscience.cdk.interfaces.IAtomContainer; 33 import org.openscience.cdk.interfaces.IBond; 34 import org.openscience.cdk.interfaces.IStereoElement; 35 import org.openscience.cdk.isomorphism.matchers.Expr; 36 import org.openscience.cdk.isomorphism.matchers.QueryAtom; 37 import org.openscience.cdk.isomorphism.matchers.QueryAtomContainer; 38 import org.openscience.cdk.isomorphism.matchers.QueryBond; 39 import org.openscience.cdk.silent.AtomContainer; 40 import org.openscience.cdk.smarts.Smarts; 41 42 import static org.hamcrest.CoreMatchers.anyOf; 43 import static org.hamcrest.CoreMatchers.is; 44 import static org.junit.Assert.assertFalse; 45 import static org.junit.Assert.assertThat; 46 import static org.junit.Assert.assertTrue; 47 import static org.openscience.cdk.isomorphism.matchers.Expr.Type.*; 48 49 public class SmartsExprReadTest { 50 expr(Expr.Type type)51 static Expr expr(Expr.Type type) { 52 return new Expr(type); 53 } 54 expr(Expr.Type type, int val)55 static Expr expr(Expr.Type type, int val) { 56 return new Expr(type, val); 57 } 58 and(Expr a, Expr b)59 static Expr and(Expr a, Expr b) { 60 return new Expr(AND, a, b); 61 } 62 or(Expr a, Expr b)63 static Expr or(Expr a, Expr b) { 64 return new Expr(OR, a, b); 65 } 66 getAtomExpr(IAtom atom)67 private static Expr getAtomExpr(IAtom atom) { 68 return ((QueryAtom) AtomRef.deref(atom)).getExpression(); 69 } 70 getBondExpr(IBond bond)71 private static Expr getBondExpr(IBond bond) { 72 return ((QueryBond) BondRef.deref(bond)).getExpression(); 73 } 74 getAtomExpr(String sma, int flav)75 static Expr getAtomExpr(String sma, int flav) { 76 IAtomContainer mol = new AtomContainer(); 77 assertTrue(Smarts.parse(mol, sma, flav)); 78 return getAtomExpr(mol.getAtom(0)); 79 } 80 getAtomExpr(String sma)81 static Expr getAtomExpr(String sma) { 82 return getAtomExpr(sma, Smarts.FLAVOR_LOOSE); 83 } 84 getBondExpr(String sma, int flav)85 static Expr getBondExpr(String sma, int flav) { 86 IAtomContainer mol = new AtomContainer(); 87 assertTrue(Smarts.parse(mol, sma, flav)); 88 return getBondExpr(mol.getBond(0)); 89 } 90 getBondExpr(String sma)91 static Expr getBondExpr(String sma) { 92 return getBondExpr(sma, Smarts.FLAVOR_LOOSE); 93 } 94 95 @Test trailingOperator()96 public void trailingOperator() { 97 IAtomContainer mol = new AtomContainer(); 98 assertFalse(Smarts.parse(mol, "[a#6,]")); 99 assertFalse(Smarts.parse(mol, "[a#6;]")); 100 assertFalse(Smarts.parse(mol, "[a#6&]")); 101 assertFalse(Smarts.parse(mol, "[a#6!]")); 102 } 103 104 @Test leadingOperator()105 public void leadingOperator() { 106 IAtomContainer mol = new AtomContainer(); 107 assertFalse(Smarts.parse(mol, "[,a#6]")); 108 assertFalse(Smarts.parse(mol, "[;a#6]")); 109 assertFalse(Smarts.parse(mol, "[&a#6]")); 110 assertTrue(Smarts.parse(mol, "[!a#6]")); 111 } 112 113 @Test trailingBondOperator()114 public void trailingBondOperator() { 115 IAtomContainer mol = new AtomContainer(); 116 assertFalse(Smarts.parse(mol, "*-,*")); 117 assertFalse(Smarts.parse(mol, "*-;*")); 118 assertFalse(Smarts.parse(mol, "*-&*")); 119 assertFalse(Smarts.parse(mol, "*-!*")); 120 } 121 122 @Test leadingBondOperator()123 public void leadingBondOperator() { 124 IAtomContainer mol = new AtomContainer(); 125 assertFalse(Smarts.parse(mol, "*,-*")); 126 assertFalse(Smarts.parse(mol, "*;-*")); 127 assertFalse(Smarts.parse(mol, "*&-*")); 128 assertTrue(Smarts.parse(mol, "*!-*")); 129 } 130 131 @Test opPrecedence1()132 public void opPrecedence1() { 133 IAtomContainer mol = new AtomContainer(); 134 assertTrue(Smarts.parse(mol, "[a#6,a#7]")); 135 Expr actual = getAtomExpr(mol.getAtom(0)); 136 Expr expected = or(and(expr(IS_AROMATIC), expr(ELEMENT, 6)), 137 and(expr(IS_AROMATIC), expr(ELEMENT, 7))); 138 assertThat(actual, is(expected)); 139 } 140 141 @Test opPrecedence2()142 public void opPrecedence2() { 143 IAtomContainer mol = new AtomContainer(); 144 assertTrue(Smarts.parse(mol, "[a;#6,#7]")); 145 Expr actual = getAtomExpr(mol.getAtom(0)); 146 Expr expected = and(expr(IS_AROMATIC), 147 or(expr(ELEMENT, 6), expr(ELEMENT, 7))); 148 assertThat(actual, is(expected)); 149 } 150 151 @Test opPrecedence3()152 public void opPrecedence3() { 153 IAtomContainer mol = new AtomContainer(); 154 assertTrue(Smarts.parse(mol, "[#6,#7;a]")); 155 Expr actual = getAtomExpr(mol.getAtom(0)); 156 Expr expected = and(expr(IS_AROMATIC), 157 or(expr(ELEMENT, 6), expr(ELEMENT, 7))); 158 assertThat(actual, is(expected)); 159 } 160 161 @Test opPrecedence4()162 public void opPrecedence4() { 163 IAtomContainer mol = new AtomContainer(); 164 assertTrue(Smarts.parse(mol, "[#6,#7a]")); 165 Expr actual = getAtomExpr(mol.getAtom(0)); 166 Expr expected = or(expr(ELEMENT, 6), 167 and(expr(ELEMENT, 7), expr(IS_AROMATIC))); 168 assertThat(actual, is(expected)); 169 } 170 171 @Test opPrecedence5()172 public void opPrecedence5() { 173 IAtomContainer mol = new AtomContainer(); 174 assertTrue(Smarts.parse(mol, "[#6&a,#7]")); 175 Expr actual = getAtomExpr(mol.getAtom(0)); 176 Expr expected = or(expr(ELEMENT, 7), 177 and(expr(ELEMENT, 6), expr(IS_AROMATIC))); 178 assertThat(actual, is(expected)); 179 } 180 181 @Test orList()182 public void orList() { 183 IAtomContainer mol = new AtomContainer(); 184 assertTrue(Smarts.parse(mol, "[F,Cl,Br,I]")); 185 Expr actual = getAtomExpr(mol.getAtom(0)); 186 Expr expected = or(expr(ELEMENT, 9), 187 or(expr(ELEMENT, 17), 188 or(expr(ELEMENT, 35), 189 expr(ELEMENT, 53)))); 190 assertThat(actual, is(expected)); 191 } 192 193 @Test explicitHydrogen()194 public void explicitHydrogen() { 195 IAtomContainer mol = new AtomContainer(); 196 assertTrue(Smarts.parse(mol, "[2H+]")); 197 Expr actual = getAtomExpr(mol.getAtom(0)); 198 Expr expected = and(expr(ISOTOPE, 2), 199 and(expr(ELEMENT, 1), expr(FORMAL_CHARGE, 1))); 200 assertThat(actual, is(expected)); 201 } 202 203 @Test explicitHydrogenNeg()204 public void explicitHydrogenNeg() { 205 IAtomContainer mol = new AtomContainer(); 206 assertTrue(Smarts.parse(mol, "[H-]")); 207 Expr actual = getAtomExpr(mol.getAtom(0)); 208 Expr expected = and(expr(ELEMENT, 1), 209 expr(FORMAL_CHARGE, -1)); 210 assertThat(actual, is(expected)); 211 } 212 213 @Test explicitHydrogenWithAtomMap()214 public void explicitHydrogenWithAtomMap() { 215 IAtomContainer mol = new AtomContainer(); 216 assertTrue(Smarts.parse(mol, "[2H+:2]")); 217 Expr actual = getAtomExpr(mol.getAtom(0)); 218 Expr expected = and(expr(ISOTOPE, 2), 219 and(expr(ELEMENT, 1), 220 expr(FORMAL_CHARGE, 1))); 221 assertThat(mol.getAtom(0).getProperty(CDKConstants.ATOM_ATOM_MAPPING, 222 Integer.class), 223 is(2)); 224 assertThat(actual, is(expected)); 225 } 226 227 @Test explicitHydrogenWithBadAtomMap()228 public void explicitHydrogenWithBadAtomMap() { 229 IAtomContainer mol = new AtomContainer(); 230 assertFalse(Smarts.parse(mol, "[2H+:]")); 231 } 232 233 @Test nonExplicitHydrogen()234 public void nonExplicitHydrogen() { 235 IAtomContainer mol = new AtomContainer(); 236 assertTrue(Smarts.parse(mol, "[2&H+]")); 237 Expr actual = getAtomExpr(mol.getAtom(0)); 238 Expr expected = and(expr(ISOTOPE, 2), 239 and(expr(TOTAL_H_COUNT, 1), 240 expr(FORMAL_CHARGE, +1))); 241 assertThat(actual, is(expected)); 242 } 243 244 @Test nonExplicitHydrogen2()245 public void nonExplicitHydrogen2() { 246 IAtomContainer mol = new AtomContainer(); 247 assertTrue(Smarts.parse(mol, "[2,H+]")); 248 Expr actual = getAtomExpr(mol.getAtom(0)); 249 Expr expected = or(expr(ISOTOPE, 2), 250 and(expr(TOTAL_H_COUNT, 1), 251 expr(FORMAL_CHARGE, +1))); 252 assertThat(actual, is(expected)); 253 } 254 255 @Test nonExplicitHydrogen3()256 public void nonExplicitHydrogen3() { 257 IAtomContainer mol = new AtomContainer(); 258 assertTrue(Smarts.parse(mol, "[2H1+]")); 259 Expr actual = getAtomExpr(mol.getAtom(0)); 260 Expr expected = and(expr(ISOTOPE, 2), 261 and(expr(TOTAL_H_COUNT, 1), 262 expr(FORMAL_CHARGE, 1))); 263 assertThat(actual, is(expected)); 264 } 265 266 @Test specifiedIsotope()267 public void specifiedIsotope() { 268 Expr actual = getAtomExpr("[!0]"); 269 Expr expected = expr(HAS_ISOTOPE); 270 assertThat(actual, is(expected)); 271 } 272 273 @Test unspecifiedIsotope()274 public void unspecifiedIsotope() { 275 Expr actual = getAtomExpr("[0]"); 276 Expr expected = expr(HAS_UNSPEC_ISOTOPE); 277 assertThat(actual, is(expected)); 278 } 279 280 @Test ringMembership()281 public void ringMembership() { 282 Expr actual = getAtomExpr("[R]"); 283 Expr expected = expr(IS_IN_RING); 284 assertThat(actual, is(expected)); 285 } 286 287 @Test ringMembership2()288 public void ringMembership2() { 289 Expr actual = getAtomExpr("[!R0]"); 290 Expr expected = expr(IS_IN_RING); 291 assertThat(actual, is(expected)); 292 } 293 294 @Test chainMembership()295 public void chainMembership() { 296 Expr actual = getAtomExpr("[R0]"); 297 Expr expected = expr(IS_IN_CHAIN); 298 assertThat(actual, is(expected)); 299 } 300 301 @Test chainMembership2()302 public void chainMembership2() { 303 Expr actual = getAtomExpr("[!R]"); 304 Expr expected = expr(IS_IN_CHAIN); 305 assertThat(actual, is(expected)); 306 } 307 308 @Test chainMembership3()309 public void chainMembership3() { 310 Expr actual = getAtomExpr("[r0]"); 311 Expr expected = expr(IS_IN_CHAIN); 312 assertThat(actual, is(expected)); 313 } 314 315 @Test chainMembership4()316 public void chainMembership4() { 317 Expr actual = getAtomExpr("[x0]"); 318 Expr expected = expr(IS_IN_CHAIN); 319 assertThat(actual, is(expected)); 320 } 321 322 @Test aromatic()323 public void aromatic() { 324 Expr actual = getAtomExpr("[a]"); 325 Expr expected = expr(IS_AROMATIC); 326 assertThat(actual, is(expected)); 327 } 328 329 @Test aromatic2()330 public void aromatic2() { 331 Expr actual = getAtomExpr("[!A]"); 332 Expr expected = expr(IS_AROMATIC); 333 assertThat(actual, is(expected)); 334 } 335 336 @Test aliphatic()337 public void aliphatic() { 338 Expr actual = getAtomExpr("[A]"); 339 Expr expected = expr(IS_ALIPHATIC); 340 assertThat(actual, is(expected)); 341 } 342 343 @Test aliphatic2()344 public void aliphatic2() { 345 Expr actual = getAtomExpr("[!a]"); 346 Expr expected = expr(IS_ALIPHATIC); 347 assertThat(actual, is(expected)); 348 } 349 350 @Test notTrue()351 public void notTrue() { 352 Expr actual = getAtomExpr("[!*]"); 353 Expr expected = expr(FALSE); 354 assertThat(actual, is(expected)); 355 } 356 357 @Test notNotTrue()358 public void notNotTrue() { 359 Expr actual = getAtomExpr("[!!*]"); 360 Expr expected = expr(TRUE); 361 assertThat(actual, is(expected)); 362 } 363 364 @Test ringCountDefault()365 public void ringCountDefault() { 366 Expr actual = getAtomExpr("[R]"); 367 Expr expected = expr(IS_IN_RING); 368 assertThat(actual, is(expected)); 369 } 370 371 @Test ringCount0()372 public void ringCount0() { 373 Expr actual = getAtomExpr("[R0]"); 374 Expr expected = expr(IS_IN_CHAIN); 375 assertThat(actual, is(expected)); 376 } 377 378 @Test ringCount()379 public void ringCount() { 380 Expr actual = getAtomExpr("[R1]"); 381 Expr expected = expr(RING_COUNT, 1); 382 assertThat(actual, is(expected)); 383 } 384 385 @Test ringCountOEChem()386 public void ringCountOEChem() { 387 Expr actual = getAtomExpr("[R2]", Smarts.FLAVOR_OECHEM); 388 Expr expected = expr(RING_BOND_COUNT, 2); 389 assertThat(actual, is(expected)); 390 } 391 392 @Test ringSmallest()393 public void ringSmallest() { 394 Expr actual = getAtomExpr("[r5]"); 395 Expr expected = expr(RING_SMALLEST, 5); 396 assertThat(actual, is(expected)); 397 } 398 399 @Test ringSmallestDefault()400 public void ringSmallestDefault() { 401 Expr actual = getAtomExpr("[r]"); 402 Expr expected = expr(IS_IN_RING); 403 assertThat(actual, is(expected)); 404 } 405 406 @Test ringSmallestInvalid()407 public void ringSmallestInvalid() { 408 IAtomContainer mol = new AtomContainer(); 409 assertTrue(Smarts.parse(mol, "[r0]")); // not in ring 410 assertFalse(Smarts.parse(mol, "[r1]")); 411 assertFalse(Smarts.parse(mol, "[r2]")); 412 assertTrue(Smarts.parse(mol, "[r3]")); 413 } 414 415 // make sure not read as C & r 416 @Test chromium()417 public void chromium() { 418 Expr actual = getAtomExpr("[Cr]"); 419 Expr expected = expr(ELEMENT, Elements.Chromium.number()); 420 assertThat(actual, is(expected)); 421 } 422 423 @Test hetero()424 public void hetero() { 425 Expr actual = getAtomExpr("[#X]"); 426 Expr expected = expr(IS_HETERO); 427 assertThat(actual, is(expected)); 428 } 429 430 @Test ringSize()431 public void ringSize() { 432 IAtomContainer mol = new AtomContainer(); 433 assertTrue(Smarts.parse(mol, "[Z8]", Smarts.FLAVOR_DAYLIGHT)); 434 Expr actual = getAtomExpr(mol.getAtom(0)); 435 Expr expected = expr(RING_SIZE, 8); 436 assertThat(actual, is(expected)); 437 } 438 439 @Test ringSize0()440 public void ringSize0() { 441 IAtomContainer mol = new AtomContainer(); 442 assertTrue(Smarts.parse(mol, "[Z0]", Smarts.FLAVOR_DAYLIGHT)); 443 Expr actual = getAtomExpr(mol.getAtom(0)); 444 Expr expected = expr(IS_IN_CHAIN); 445 assertThat(actual, is(expected)); 446 } 447 448 @Test ringSizeDefault()449 public void ringSizeDefault() { 450 IAtomContainer mol = new AtomContainer(); 451 assertTrue(Smarts.parse(mol, "[Z]", Smarts.FLAVOR_DAYLIGHT)); 452 Expr actual = getAtomExpr(mol.getAtom(0)); 453 Expr expected = expr(IS_IN_RING); 454 assertThat(actual, is(expected)); 455 } 456 457 @Test adjacentHeteroCount()458 public void adjacentHeteroCount() { 459 IAtomContainer mol = new AtomContainer(); 460 assertTrue(Smarts.parse(mol, "[Z2]", Smarts.FLAVOR_CACTVS)); 461 Expr actual = getAtomExpr(mol.getAtom(0)); 462 Expr expected = expr(ALIPHATIC_HETERO_SUBSTITUENT_COUNT, 2); 463 assertThat(actual, is(expected)); 464 } 465 466 @Test adjacentHetero()467 public void adjacentHetero() { 468 IAtomContainer mol = new AtomContainer(); 469 assertTrue(Smarts.parse(mol, "[Z]", Smarts.FLAVOR_CACTVS)); 470 Expr actual = getAtomExpr(mol.getAtom(0)); 471 Expr expected = expr(HAS_ALIPHATIC_HETERO_SUBSTITUENT); 472 assertThat(actual, is(expected)); 473 } 474 475 @Test adjacentHetero0()476 public void adjacentHetero0() { 477 IAtomContainer mol = new AtomContainer(); 478 assertTrue(Smarts.parse(mol, "[Z0]", Smarts.FLAVOR_CACTVS)); 479 Expr actual = getAtomExpr(mol.getAtom(0)); 480 Expr expected = expr(HAS_ALIPHATIC_HETERO_SUBSTITUENT).negate(); 481 assertThat(actual, is(expected)); 482 } 483 484 @Test valence()485 public void valence() { 486 Expr actual = getAtomExpr("[v4]"); 487 Expr expected = expr(VALENCE, 4); 488 assertThat(actual, is(expected)); 489 } 490 491 @Test valenceDefault()492 public void valenceDefault() { 493 Expr actual = getAtomExpr("[v]"); 494 Expr expected = expr(VALENCE, 1); 495 assertThat(actual, is(expected)); 496 } 497 498 @Test degree()499 public void degree() { 500 Expr actual = getAtomExpr("[D4]"); 501 Expr expected = expr(DEGREE, 4); 502 assertThat(actual, is(expected)); 503 } 504 505 @Test degreeDefault()506 public void degreeDefault() { 507 Expr actual = getAtomExpr("[D]"); 508 Expr expected = expr(DEGREE, 1); 509 assertThat(actual, is(expected)); 510 } 511 512 @Test degreeCDKLegacy()513 public void degreeCDKLegacy() { 514 Expr actual = getAtomExpr("[D4]", Smarts.FLAVOR_CDK_LEGACY); 515 Expr expected = expr(HEAVY_DEGREE, 4); 516 assertThat(actual, is(expected)); 517 } 518 519 @Test degreeCDKLegacyDefault()520 public void degreeCDKLegacyDefault() { 521 Expr actual = getAtomExpr("[D]", Smarts.FLAVOR_CDK_LEGACY); 522 Expr expected = expr(HEAVY_DEGREE, 1); 523 assertThat(actual, is(expected)); 524 } 525 526 @Test connectivity()527 public void connectivity() { 528 Expr actual = getAtomExpr("[X4]"); 529 Expr expected = expr(TOTAL_DEGREE, 4); 530 assertThat(actual, is(expected)); 531 } 532 533 @Test connectivityDefault()534 public void connectivityDefault() { 535 Expr actual = getAtomExpr("[X]"); 536 Expr expected = expr(TOTAL_DEGREE, 1); 537 assertThat(actual, is(expected)); 538 } 539 540 @Test totalHCount()541 public void totalHCount() { 542 Expr actual = getAtomExpr("[H2]"); 543 Expr expected = expr(TOTAL_H_COUNT, 2); 544 assertThat(actual, is(expected)); 545 } 546 547 @Test implHCount()548 public void implHCount() { 549 Expr actual = getAtomExpr("[h2]"); 550 Expr expected = expr(IMPL_H_COUNT, 2); 551 assertThat(actual, is(expected)); 552 } 553 554 @Test hasImplHCount()555 public void hasImplHCount() { 556 Expr actual = getAtomExpr("[h]"); 557 Expr expected = expr(HAS_IMPLICIT_HYDROGEN); 558 assertThat(actual, is(expected)); 559 } 560 561 @Test ringBondCount()562 public void ringBondCount() { 563 Expr actual = getAtomExpr("[x2]"); 564 Expr expected = expr(RING_BOND_COUNT, 2); 565 assertThat(actual, is(expected)); 566 } 567 568 @Test ringBondCount0()569 public void ringBondCount0() { 570 Expr actual = getAtomExpr("[x0]"); 571 Expr expected = expr(IS_IN_CHAIN); 572 assertThat(actual, is(expected)); 573 } 574 575 @Test ringBondCount1()576 public void ringBondCount1() { 577 assertFalse(Smarts.parse(new QueryAtomContainer(null), "[x1]")); 578 } 579 580 @Test ringBondCountDefault()581 public void ringBondCountDefault() { 582 Expr actual = getAtomExpr("[x]"); 583 Expr expected = expr(IS_IN_RING); 584 assertThat(actual, is(expected)); 585 } 586 587 @Test formalChargeNeg()588 public void formalChargeNeg() { 589 Expr actual = getAtomExpr("[-1]"); 590 Expr expected = expr(FORMAL_CHARGE, -1); 591 assertThat(actual, is(expected)); 592 } 593 594 @Test formalChargeNegNeg()595 public void formalChargeNegNeg() { 596 Expr actual = getAtomExpr("[--]"); 597 Expr expected = expr(FORMAL_CHARGE, -2); 598 assertThat(actual, is(expected)); 599 } 600 601 @Test formalChargePos()602 public void formalChargePos() { 603 Expr actual = getAtomExpr("[+]"); 604 Expr expected = expr(FORMAL_CHARGE, +1); 605 assertThat(actual, is(expected)); 606 } 607 608 @Test formalChargePosPos()609 public void formalChargePosPos() { 610 Expr actual = getAtomExpr("[++]"); 611 Expr expected = expr(FORMAL_CHARGE, +2); 612 assertThat(actual, is(expected)); 613 } 614 615 @Test atomMaps()616 public void atomMaps() { 617 IAtomContainer mol = new QueryAtomContainer(null); 618 assertFalse(Smarts.parse(mol, "[:10]")); 619 assertTrue(Smarts.parse(mol, "[*:10]")); 620 assertThat(mol.getAtom(0).getProperty(CDKConstants.ATOM_ATOM_MAPPING, Integer.class), 621 is(10)); 622 } 623 624 @Test periodicTableGroup()625 public void periodicTableGroup() { 626 Expr actual = getAtomExpr("[#G16]", Smarts.FLAVOR_MOE); 627 Expr expected = expr(PERIODIC_GROUP, 16); 628 assertThat(actual, is(expected)); 629 } 630 631 @Test periodicTableGroupCDKLegacy()632 public void periodicTableGroupCDKLegacy() { 633 Expr actual = getAtomExpr("[G16]", Smarts.FLAVOR_CDK_LEGACY); 634 Expr expected = expr(PERIODIC_GROUP, 16); 635 assertThat(actual, is(expected)); 636 } 637 638 @Test insaturationCactvs()639 public void insaturationCactvs() { 640 Expr actual = getAtomExpr("[G1]", Smarts.FLAVOR_CACTVS); 641 Expr expected = expr(INSATURATION, 1); 642 assertThat(actual, is(expected)); 643 } 644 645 @Test insaturationCactvsOrMoe()646 public void insaturationCactvsOrMoe() { 647 assertThat(getAtomExpr("[i1]", Smarts.FLAVOR_CACTVS), 648 is(expr(INSATURATION, 1))); 649 assertThat(getAtomExpr("[i1]", Smarts.FLAVOR_MOE), 650 is(expr(INSATURATION, 1))); 651 } 652 653 @Test heteroSubCountCactvs()654 public void heteroSubCountCactvs() { 655 assertThat(getAtomExpr("[z]", Smarts.FLAVOR_CACTVS), 656 is(expr(HAS_HETERO_SUBSTITUENT))); 657 assertThat(getAtomExpr("[z1]", Smarts.FLAVOR_CACTVS), 658 is(expr(HETERO_SUBSTITUENT_COUNT, 1))); 659 } 660 661 @Test hybridisationNumber()662 public void hybridisationNumber() { 663 Expr actual = getAtomExpr("[^2]", Smarts.FLAVOR_OECHEM); 664 Expr expected = expr(HYBRIDISATION_NUMBER, 2); 665 assertThat(actual, is(expected)); 666 } 667 668 @Test hybridisationNumberDaylight()669 public void hybridisationNumberDaylight() { 670 assertFalse(Smarts.parse(new QueryAtomContainer(null), 671 "[^2]", 672 Smarts.FLAVOR_DAYLIGHT)); 673 } 674 675 @Test atomStereoLeft()676 public void atomStereoLeft() { 677 Expr actual = getAtomExpr("[@]"); 678 Expr expected = expr(STEREOCHEMISTRY, IStereoElement.LEFT); 679 assertThat(actual, is(expected)); 680 } 681 682 @Test atomStereoRight()683 public void atomStereoRight() { 684 Expr actual = getAtomExpr("[@@]"); 685 Expr expected = expr(STEREOCHEMISTRY, IStereoElement.RIGHT); 686 assertThat(actual, is(expected)); 687 } 688 689 @Test atomStereoLeftOrUnspec()690 public void atomStereoLeftOrUnspec() { 691 Expr actual = getAtomExpr("[@?]"); 692 Expr expected = or(expr(STEREOCHEMISTRY, IStereoElement.LEFT), 693 expr(STEREOCHEMISTRY, 0)); 694 assertThat(actual, is(expected)); 695 } 696 697 @Test atomStereoSimpleLeft()698 public void atomStereoSimpleLeft() { 699 Expr actual = getAtomExpr("[C@H]"); 700 assertThat(actual, is(new Expr(ALIPHATIC_ELEMENT, 6) 701 .and(new Expr(STEREOCHEMISTRY, 1)) 702 .and(new Expr(TOTAL_H_COUNT, 1)))); 703 } 704 705 @Test badExprs()706 public void badExprs() { 707 IAtomContainer mol = new AtomContainer(); 708 assertFalse(Smarts.parse(mol, "*-,*")); 709 assertFalse(Smarts.parse(mol, "*-;*")); 710 assertFalse(Smarts.parse(mol, "*-!*")); 711 assertFalse(Smarts.parse(mol, "*-&*")); 712 assertFalse(Smarts.parse(mol, "*!*")); 713 assertFalse(Smarts.parse(mol, "*,*")); 714 assertFalse(Smarts.parse(mol, "*;*")); 715 assertFalse(Smarts.parse(mol, "*&*")); 716 assertFalse(Smarts.parse(mol, "*,-*")); 717 } 718 719 @Test singleOrAromatic()720 public void singleOrAromatic() { 721 Expr actual = getBondExpr("**"); 722 Expr expected = expr(SINGLE_OR_AROMATIC); 723 assertThat(expected, is(actual)); 724 } 725 726 @Test singleBond()727 public void singleBond() { 728 Expr actual = getBondExpr("*-*"); 729 Expr expected = expr(ALIPHATIC_ORDER, 1); 730 assertThat(expected, is(actual)); 731 } 732 733 @Test doubleBond()734 public void doubleBond() { 735 Expr actual = getBondExpr("*=*"); 736 Expr expected = expr(ALIPHATIC_ORDER, 2); 737 assertThat(expected, is(actual)); 738 } 739 740 @Test tripleBond()741 public void tripleBond() { 742 Expr actual = getBondExpr("*#*"); 743 Expr expected = expr(ALIPHATIC_ORDER, 3); 744 assertThat(expected, is(actual)); 745 } 746 747 @Test quadBond()748 public void quadBond() { 749 Expr actual = getBondExpr("*$*"); 750 Expr expected = expr(ALIPHATIC_ORDER, 4); 751 assertThat(expected, is(actual)); 752 } 753 754 @Test aromaticBond()755 public void aromaticBond() { 756 Expr actual = getBondExpr("*:*"); 757 Expr expected = expr(IS_AROMATIC); 758 assertThat(expected, is(actual)); 759 } 760 761 @Test aliphaticBond()762 public void aliphaticBond() { 763 Expr actual = getBondExpr("*!:*"); 764 Expr expected = expr(IS_ALIPHATIC); 765 assertThat(expected, is(actual)); 766 } 767 768 @Test chainBond()769 public void chainBond() { 770 Expr actual = getBondExpr("*!@*"); 771 Expr expected = expr(IS_IN_CHAIN); 772 assertThat(expected, is(actual)); 773 } 774 775 @Test anyBond()776 public void anyBond() { 777 Expr actual = getBondExpr("*~*"); 778 Expr expected = expr(TRUE); 779 assertThat(expected, is(actual)); 780 } 781 782 @Test singleOrDouble()783 public void singleOrDouble() { 784 Expr actual = getBondExpr("*-,=*"); 785 Expr expected = or(expr(ALIPHATIC_ORDER, 1), 786 expr(ALIPHATIC_ORDER, 2)); 787 assertThat(expected, is(actual)); 788 } 789 790 @Test operatorPrecedence()791 public void operatorPrecedence() { 792 Expr actual = getBondExpr("*@;-,=*"); 793 Expr expected = and(expr(IS_IN_RING), 794 or(expr(ALIPHATIC_ORDER, 1), 795 expr(ALIPHATIC_ORDER, 2))); 796 assertThat(expected, is(actual)); 797 } 798 799 @Test notInRing()800 public void notInRing() { 801 Expr actual = getBondExpr("*!@*"); 802 Expr expected = expr(IS_IN_CHAIN); 803 assertThat(expected, is(actual)); 804 } 805 806 @Test notAromatic()807 public void notAromatic() { 808 Expr actual = getBondExpr("*!:*"); 809 Expr expected = expr(IS_ALIPHATIC); 810 assertThat(expected, is(actual)); 811 } 812 813 @Test notNotWildcard()814 public void notNotWildcard() { 815 Expr actual = getBondExpr("*!!~*"); 816 Expr expected = expr(TRUE); 817 assertThat(expected, is(actual)); 818 } 819 820 @Test testAliphaticSymbols()821 public void testAliphaticSymbols() { 822 for (Elements e : Elements.values()) { 823 int len = e.symbol().length(); 824 if (len == 1 || len == 2) { 825 String smarts = "[" + e.symbol() + "]"; 826 QueryAtomContainer mol = new QueryAtomContainer(null); 827 assertTrue(smarts, Smarts.parse(mol, smarts)); 828 Expr expr = getAtomExpr(mol.getAtom(0)); 829 assertThat(expr, anyOf(is(new Expr(ELEMENT, e.number())), 830 is(new Expr(ALIPHATIC_ELEMENT, e.number())))); 831 } 832 } 833 } 834 835 @Test testAromaticSymbols()836 public void testAromaticSymbols() { 837 assertThat(getAtomExpr("[b]"), is(new Expr(AROMATIC_ELEMENT, 5))); 838 assertThat(getAtomExpr("[c]"), is(new Expr(AROMATIC_ELEMENT, 6))); 839 assertThat(getAtomExpr("[n]"), is(new Expr(AROMATIC_ELEMENT, 7))); 840 assertThat(getAtomExpr("[o]"), is(new Expr(AROMATIC_ELEMENT, 8))); 841 assertThat(getAtomExpr("[al]"), is(new Expr(AROMATIC_ELEMENT, 13))); 842 assertThat(getAtomExpr("[si]"), is(new Expr(AROMATIC_ELEMENT, 14))); 843 assertThat(getAtomExpr("[p]"), is(new Expr(AROMATIC_ELEMENT, 15))); 844 assertThat(getAtomExpr("[s]"), is(new Expr(AROMATIC_ELEMENT, 16))); 845 assertThat(getAtomExpr("[as]"), is(new Expr(AROMATIC_ELEMENT, 33))); 846 assertThat(getAtomExpr("[se]"), is(new Expr(AROMATIC_ELEMENT, 34))); 847 assertThat(getAtomExpr("[sb]"), is(new Expr(AROMATIC_ELEMENT, 51))); 848 assertThat(getAtomExpr("[te]"), is(new Expr(AROMATIC_ELEMENT, 52))); 849 } 850 851 @Test testBadSymbols()852 public void testBadSymbols() { 853 assertFalse(Smarts.parse(new QueryAtomContainer(null), "[L]")); 854 assertFalse(Smarts.parse(new QueryAtomContainer(null), "[J]")); 855 assertFalse(Smarts.parse(new QueryAtomContainer(null), "[Q]")); 856 assertFalse(Smarts.parse(new QueryAtomContainer(null), "[G]")); 857 assertFalse(Smarts.parse(new QueryAtomContainer(null), "[T]")); 858 assertFalse(Smarts.parse(new QueryAtomContainer(null), "[M]")); 859 assertFalse(Smarts.parse(new QueryAtomContainer(null), "[E]")); 860 assertFalse(Smarts.parse(new QueryAtomContainer(null), "[t]")); 861 assertFalse(Smarts.parse(new QueryAtomContainer(null), "[?]")); 862 } 863 864 @Test testRecursive()865 public void testRecursive() { 866 assertTrue(Smarts.parse(new QueryAtomContainer(null), "[$(*OC)]")); 867 assertFalse(Smarts.parse(new QueryAtomContainer(null), "[$*OC)]")); 868 assertFalse(Smarts.parse(new QueryAtomContainer(null), "[$(*OC]")); 869 assertTrue(Smarts.parse(new QueryAtomContainer(null), "[$((*[O-].[Na+]))]")); 870 assertFalse(Smarts.parse(new QueryAtomContainer(null), "[$([J])]")); 871 } 872 873 // recursive SMARTS with single atoms should be 'lifted' up to a single 874 // non-recursive expression 875 @Test testTrivialRecursive()876 public void testTrivialRecursive() { 877 Expr expr = getAtomExpr("[$(F),$(Cl),$(Br)]"); 878 assertThat(expr, is(or(expr(ELEMENT, 9), 879 or(expr(ELEMENT, 17), 880 expr(ELEMENT, 35))))); 881 } 882 883 // must always be read/written in SMARTS as recursive but we can lift 884 // the expression up to the top level 885 @Test testTrivialRecursive2()886 public void testTrivialRecursive2() { 887 Expr expr = getAtomExpr("[!$([F,Cl,Br])]"); 888 assertThat(expr, is(or(expr(ELEMENT, 9), 889 or(expr(ELEMENT, 17), 890 expr(ELEMENT, 35))).negate())); 891 } 892 893 @Test ringOpenCloseInconsistency()894 public void ringOpenCloseInconsistency() { 895 assertFalse(Smarts.parse(new QueryAtomContainer(null), "C=1CC-,=1")); 896 assertFalse(Smarts.parse(new QueryAtomContainer(null), "C=1CC-1"));; 897 } 898 899 @Test ringOpenCloseConsistency()900 public void ringOpenCloseConsistency() { 901 assertTrue(Smarts.parse(new QueryAtomContainer(null), "C-,=1CC-,=1")); 902 assertTrue(Smarts.parse(new QueryAtomContainer(null), "C!~1CC!~1")); 903 } 904 905 @Test degreeRange()906 public void degreeRange() { 907 Expr expr = getAtomExpr("[D{1-3}]"); 908 assertThat(expr, is(or(expr(DEGREE, 1), 909 or(expr(DEGREE, 2), 910 expr(DEGREE, 3))))); 911 } 912 913 @Test implHRange()914 public void implHRange() { 915 Expr expr = getAtomExpr("[h{1-3}]"); 916 assertThat(expr, is(or(expr(IMPL_H_COUNT, 1), 917 or(expr(IMPL_H_COUNT, 2), 918 expr(IMPL_H_COUNT, 3))))); 919 } 920 921 @Test totalHCountRange()922 public void totalHCountRange() { 923 Expr expr = getAtomExpr("[H{1-3}]"); 924 assertThat(expr, is(or(expr(TOTAL_H_COUNT, 1), 925 or(expr(TOTAL_H_COUNT, 2), 926 expr(TOTAL_H_COUNT, 3))))); 927 } 928 929 @Test valenceRange()930 public void valenceRange() { 931 Expr expr = getAtomExpr("[v{1-3}]"); 932 assertThat(expr, is(or(expr(VALENCE, 1), 933 or(expr(VALENCE, 2), 934 expr(VALENCE, 3))))); 935 } 936 937 @Test ringBondCountRange()938 public void ringBondCountRange() { 939 Expr expr = getAtomExpr("[x{2-4}]"); 940 assertThat(expr, is(or(expr(RING_BOND_COUNT, 2), 941 or(expr(RING_BOND_COUNT, 3), 942 expr(RING_BOND_COUNT, 4))))); 943 } 944 945 @Test ringSmallestSizeCountRange()946 public void ringSmallestSizeCountRange() { 947 Expr expr = getAtomExpr("[r{5-7}]"); 948 assertThat(expr, is(or(expr(RING_SMALLEST, 5), 949 or(expr(RING_SMALLEST, 6), 950 expr(RING_SMALLEST, 7))))); 951 } 952 953 @Test supportInsaturatedByDefault()954 public void supportInsaturatedByDefault() { 955 Expr expr = getAtomExpr("[i]"); 956 assertThat(expr, is(expr(UNSATURATED))); 957 } 958 959 @Test supportHGt()960 public void supportHGt() { 961 Expr expr = getAtomExpr("[H>1]"); 962 assertThat(expr, is(and(expr(TOTAL_H_COUNT, 0).negate(), 963 expr(TOTAL_H_COUNT, 1).negate()))); 964 } 965 966 @Test supportHLt()967 public void supportHLt() { 968 Expr expr = getAtomExpr("[H<2]"); 969 assertThat(expr, is(or(expr(TOTAL_H_COUNT, 0), 970 expr(TOTAL_H_COUNT, 1)))); 971 } 972 973 @Test supportDGt()974 public void supportDGt() { 975 Expr expr = getAtomExpr("[D>1]"); 976 assertThat(expr, is(and(expr(DEGREE, 0).negate(), 977 expr(DEGREE, 1).negate()))); 978 } 979 980 @Test supportDLt()981 public void supportDLt() { 982 Expr expr = getAtomExpr("[D<2]"); 983 assertThat(expr, is(or(expr(DEGREE, 0), 984 expr(DEGREE, 1)))); 985 } 986 }