context: /* Copyright (C) 2004-2007  Egon Willighagen <egonw@users.sf.net>
   *
   * Contact: cdk-devel@lists.sourceforge.net
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public License
   * as published by the Free Software Foundation; either version 2.1
   * of the License, or (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   */
  
  using Microsoft.VisualStudio.TestTools.UnitTesting;
  using NCDK.Aromaticities;
  using NCDK.Common.Base;
  using NCDK.Graphs;
  using NCDK.IO;
  using NCDK.Isomorphisms;
  using NCDK.Tools.Manipulator;
  using System;
  using System.Diagnostics;
  using System.Linq;
  
  namespace NCDK.Smiles.SMARTS.Parser
  {
      /// <summary>
      /// Unit test routines for the SMARTS substructure search.
      /// </summary>
      // @author Dazhi Jiao
      // @cdk.module test-smarts
      // @cdk.require ant1.6
      [TestClass()]
      public class SMARTSSearchTest : CDKTestCase
      {
          private UniversalIsomorphismTester uiTester = new UniversalIsomorphismTester();
  
          internal static IAtomContainer CreateFromSmiles(string smiles)
          {
              return CreateFromSmiles(smiles, false);
          }
  
          internal static IAtomContainer SmilesAtomTyped(string smiles)
          {
              IAtomContainer molecule = CreateFromSmiles(smiles, false);
              AtomContainerManipulator.PercieveAtomTypesAndConfigureAtoms(molecule);
              return molecule;
          }
  
          internal static IAtomContainer CreateFromSmiles(string smiles, bool perserveAromaticity)
          {
              var sp = new SmilesParser(CDK.Builder, !perserveAromaticity);
              return sp.ParseSmiles(smiles);
          }
  
          internal static SMARTSQueryTool CreateFromSmarts(string smarts)
          {
              SMARTSQueryTool sqt = new SMARTSQueryTool(smarts);
              return sqt;
          }
  
          internal static int[] Match(SMARTSQueryTool sqt, IAtomContainer m)
          {
              bool status = sqt.Matches(m);
              if (status)
              {
                  return new int[] { sqt.MatchesCount, sqt.GetUniqueMatchingAtoms().Count() };
              }
              else
              {
                  return new int[] { 0, 0 };
              }
          }
  
          internal static int[] Match(string smarts, string smiles)
          {
              return Match(CreateFromSmarts(smarts), CreateFromSmiles(smiles));
          }
  
          [TestMethod()]
          public void TestMoleculeFromSDF()
          {
              var filename = "cnssmarts.sdf";
              var ins = ResourceLoader.GetAsStream(GetType(), filename);
              DefaultChemObjectReader reader = new MDLV2000Reader(ins);
              var content = reader.Read(CDK.Builder.NewChemFile());
              var cList = ChemFileManipulator.GetAllAtomContainers(content).ToReadOnlyList();
              IAtomContainer atomContainer = cList[0];
  
              SMARTSQueryTool sqt = new SMARTSQueryTool("[NX3;h1,h2,H1,H2;!$(NC=O)]");
              bool status = sqt.Matches(atomContainer);
              Assert.AreEqual(true, status);
  
              int nmatch = sqt.MatchesCount;
              int nqmatch = sqt.GetUniqueMatchingAtoms().Count();
  
              Assert.AreEqual(3, nmatch);
              Assert.AreEqual(3, nqmatch);
  
              sqt.Smarts = "[ND3]";
              status = sqt.Matches(atomContainer);
              Assert.AreEqual(false, status);
          }
  
          [TestMethod()]
          public void TestRGraphBond()
          {
              var query = SMARTSParser.Parse("CC=O");
              Debug.WriteLine("Query c:c: " + query.ToString());
              var sp = CDK.SmilesParser;
  
              var atomContainer = sp.ParseSmiles("CCC=O"); // benzene, aromatic
              Assert.IsTrue(uiTester.IsSubgraph(atomContainer, query));
          }
  
          [TestMethod()]
          public void TestAromaticBond()
          {
              var query = SMARTSParser.Parse("c:c");
              Debug.WriteLine("Query c:c: " + query.ToString());
              var sp = new SmilesParser(CDK.Builder, false);
              var atomContainer = sp.ParseSmiles("c1ccccc1"); // benzene, aromatic
              Assert.IsTrue(uiTester.IsSubgraph(atomContainer, query));
  
              atomContainer = sp.ParseSmiles("C1CCCCC1"); // hexane, not aromatic
              Assert.IsFalse(uiTester.IsSubgraph(atomContainer, query));
          }
  
          [TestMethod()]
          public void TestSingleBond()
          {
              var query = SMARTSParser.Parse("C-C");
              Debug.WriteLine("Query C-C: " + query.ToString());
              var sp = CDK.SmilesParser;
  
              var atomContainer = sp.ParseSmiles("CCC");
              Assert.IsTrue(uiTester.IsSubgraph(atomContainer, query));
  
              atomContainer = sp.ParseSmiles("C=C");
              Assert.IsFalse(uiTester.IsSubgraph(atomContainer, query));
  
              atomContainer = sp.ParseSmiles("C#C");
              Assert.IsFalse(uiTester.IsSubgraph(atomContainer, query));
          }
  
          [TestMethod()]
          public void TestDoubleBond()
          {
              var query = SMARTSParser.Parse("C=C");
              Debug.WriteLine("Query C=C: " + query.ToString());
              var sp = CDK.SmilesParser;
  
              var atomContainer = sp.ParseSmiles("CCC");
              Assert.IsFalse(uiTester.IsSubgraph(atomContainer, query));
  
              atomContainer = sp.ParseSmiles("C=C");
              Assert.IsTrue(uiTester.IsSubgraph(atomContainer, query));
  
              atomContainer = sp.ParseSmiles("C#C");
              Assert.IsFalse(uiTester.IsSubgraph(atomContainer, query));
          }
  
          [TestMethod()]
          public void TestTripleBond()
          {
              var query = SMARTSParser.Parse("C#C");
              Debug.WriteLine("Query C#C: " + query.ToString());
              var sp = CDK.SmilesParser;
  
              var atomContainer = sp.ParseSmiles("CCC");
              Assert.IsFalse(uiTester.IsSubgraph(atomContainer, query));
  
              atomContainer = sp.ParseSmiles("C=C");
              Assert.IsFalse(uiTester.IsSubgraph(atomContainer, query));
  
              atomContainer = sp.ParseSmiles("C#C");
              Assert.IsTrue(uiTester.IsSubgraph(atomContainer, query));
          }
  
          [TestMethod()]
          public void TestAnyOrderBond()
          {
              var query = SMARTSParser.Parse("C~C");
              Debug.WriteLine("Query C~C: " + query.ToString());
              var sp = CDK.SmilesParser;
  
              var atomContainer = sp.ParseSmiles("CCC");
              Assert.IsTrue(uiTester.IsSubgraph(atomContainer, query));
  
              atomContainer = sp.ParseSmiles("C=C");
              Assert.IsTrue(uiTester.IsSubgraph(atomContainer, query));
  
              atomContainer = sp.ParseSmiles("C#C");
              Assert.IsTrue(uiTester.IsSubgraph(atomContainer, query));
          }
  
          [TestMethod()]
          public void TestAnyAtom()
          {
              var query = SMARTSParser.Parse("C*C");
              Debug.WriteLine("Query C*C: " + query.ToString());
              var sp = CDK.SmilesParser;
  
              var atomContainer = sp.ParseSmiles("CCC");
              Assert.IsTrue(uiTester.IsSubgraph(atomContainer, query));
  
              atomContainer = sp.ParseSmiles("CNC");
              Assert.IsTrue(uiTester.IsSubgraph(atomContainer, query));
  
              atomContainer = sp.ParseSmiles("CCN");
              Assert.IsFalse(uiTester.IsSubgraph(atomContainer, query));
          }
  
          [TestMethod()]
          public void TestAliphaticAtom()
          {
              var query = SMARTSParser.Parse("CAC");
              Debug.WriteLine("Query CAC: " + query.ToString());
              var sp = CDK.SmilesParser;
  
              var atomContainer = sp.ParseSmiles("CCC");
              Assert.IsTrue(uiTester.IsSubgraph(atomContainer, query));
  
              atomContainer = sp.ParseSmiles("CNC");
              Assert.IsTrue(uiTester.IsSubgraph(atomContainer, query));
  
              atomContainer = sp.ParseSmiles("c1ccccc1"); // benzene, aromatic
              Assert.IsFalse(uiTester.IsSubgraph(atomContainer, query));
          }
  
          [TestMethod()]
          public void TestAromaticAtom()
          {
              var query = SMARTSParser.Parse("aaa");
              Debug.WriteLine("Query CaC: " + query.ToString());
              var sp = new SmilesParser(CDK.Builder, false);
  
              var atomContainer = sp.ParseSmiles("CCC");
              Assert.IsFalse(uiTester.IsSubgraph(atomContainer, query));
  
              atomContainer = sp.ParseSmiles("c1ccccc1"); // benzene, aromatic
              Assert.IsTrue(uiTester.IsSubgraph(atomContainer, query));
          }
  
          [TestMethod()]
          public void TestSymbolQueryAtom()
          {
              var query = SMARTSParser.Parse("CCC");
              Debug.WriteLine("Query CAC: " + query.ToString());
              var sp = CDK.SmilesParser;
  
              var atomContainer = sp.ParseSmiles("CCC");
              Assert.IsTrue(uiTester.IsSubgraph(atomContainer, query));
  
              atomContainer = sp.ParseSmiles("CNC");
              Assert.IsFalse(uiTester.IsSubgraph(atomContainer, query));
  
              atomContainer = sp.ParseSmiles("c1ccccc1"); // benzene, aromatic
              Assert.IsFalse(uiTester.IsSubgraph(atomContainer, query));
          }
  
          /// <summary>
          /// From http://www.daylight.com/dayhtml_tutorials/languages/smarts/index.html
          /// </summary>
          [TestMethod()]
          public void TestPropertyCharge1()
          {
              int[] results = Match("[+1]", "[OH-].[Mg+2]");
              Assert.AreEqual(0, results[0]);
              Assert.AreEqual(0, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyCharge2()
          {
              int[] results = Match("[+1]", "COCC(O)Cn1ccnc1[N+](=O)[O-]");
              Assert.AreEqual(1, results[0]);
              Assert.AreEqual(1, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyCharge3()
          {
              int[] results = Match("[+1]", "[NH4+]");
              Assert.AreEqual(1, results[0]);
              Assert.AreEqual(1, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyCharge4()
          {
              int[] results = Match("[+1]", "CN1C(=O)N(C)C(=O)C(N(C)C=N2)=C12");
              Assert.AreEqual(0, results[0]);
              Assert.AreEqual(0, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyCharge5()
          {
              int[] results = Match("[+1]", "[Cl-].[Cl-].NC(=O)c2cc[n+](COC[n+]1ccccc1C=NO)cc2");
              Assert.AreEqual(2, results[0]);
              Assert.AreEqual(2, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAromatic1()
          {
              int[] results = Match("[a]", "c1cc(C)c(N)cc1");
              Assert.AreEqual(6, results[0]);
              Assert.AreEqual(6, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAromatic2()
          {
              int[] results = Match("[a]", "c1c(C)c(N)cnc1");
              Assert.AreEqual(6, results[0]);
              Assert.AreEqual(6, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAromatic3()
          {
              int[] results = Match("[a]", "c1(C)c(N)cco1");
              Assert.AreEqual(5, results[0]);
              Assert.AreEqual(5, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAromatic4()
          {
              int[] results = Match("[a]", "c1c(C)c(N)c[nH]1");
              Assert.AreEqual(5, results[0]);
              Assert.AreEqual(5, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAromatic5()
          {
              int[] results = Match("[a]", "O=n1ccccc1");
              Assert.AreEqual(6, results[0]);
              Assert.AreEqual(6, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAromatic6()
          {
              int[] results = Match("[a]", "[O-][n+]1ccccc1");
              Assert.AreEqual(6, results[0]);
              Assert.AreEqual(6, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAromatic7()
          {
              int[] results = Match("[a]", "c1ncccc1C1CCCN1C");
              Assert.AreEqual(6, results[0]);
              Assert.AreEqual(6, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAromatic8()
          {
              int[] results = Match("[a]", "c1ccccc1C(=O)OC2CC(N3C)CCC3C2C(=O)OC");
              Assert.AreEqual(6, results[0]);
              Assert.AreEqual(6, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAliphatic1()
          {
              int[] results = Match("[A]", "c1cc(C)c(N)cc1");
              Assert.AreEqual(2, results[0]);
              Assert.AreEqual(2, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAliphatic2()
          {
              int[] results = Match("[A]", "CCO");
              Assert.AreEqual(3, results[0]);
              Assert.AreEqual(3, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAliphatic3()
          {
              int[] results = Match("[A]", "C=CC=CC=C");
              Assert.AreEqual(6, results[0]);
              Assert.AreEqual(6, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAliphatic4()
          {
              int[] results = Match("[A]", "CC(C)(C)C");
              Assert.AreEqual(5, results[0]);
              Assert.AreEqual(5, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAliphatic5()
          {
              int[] results = Match("[A]", "CCN(CC)C(=O)C1CN(C)C2CC3=CNc(ccc4)c3c4C2=C1");
              Assert.AreEqual(15, results[0]);
              Assert.AreEqual(15, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAliphatic6()
          {
              int[] results = Match("[A]", "N12CCC36C1CC(C(C2)=CCOC4CC5=O)C4C3N5c7ccccc76");
              Assert.AreEqual(19, results[0]);
              Assert.AreEqual(19, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAtomicNumber1()
          {
              int[] results = Match("[#6]", "c1cc(C)c(N)cc1");
              Assert.AreEqual(7, results[0]);
              Assert.AreEqual(7, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAtomicNumber2()
          {
              int[] results = Match("[#6]", "CCO");
              Assert.AreEqual(2, results[0]);
              Assert.AreEqual(2, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAtomicNumber3()
          {
              int[] results = Match("[#6]", "C=CC=CC=C-O");
              Assert.AreEqual(6, results[0]);
              Assert.AreEqual(6, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAtomicNumber4()
          {
              int[] results = Match("[#6]", "CC(C)(C)C");
              Assert.AreEqual(5, results[0]);
              Assert.AreEqual(5, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAtomicNumber5()
          {
              int[] results = Match("[#6]", "COc1cc2c(ccnc2cc1)C(O)C4CC(CC3)C(C=C)CN34");
              Assert.AreEqual(20, results[0]);
              Assert.AreEqual(20, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAtomicNumber6()
          {
              int[] results = Match("[#6]", "C123C5C(O)C=CC2C(N(C)CC1)Cc(ccc4O)c3c4O5");
              Assert.AreEqual(17, results[0]);
              Assert.AreEqual(17, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAtomicNumber7()
          {
              int[] results = Match("[#6]", "C123C5C(OC(=O)C)C=CC2C(N(C)CC1)Cc(ccc4OC(=O)C)c3c4O5");
              Assert.AreEqual(21, results[0]);
              Assert.AreEqual(21, results[1]);
          }
  
          // @cdk.bug 2686473
          [TestMethod()]
          public void TestPropertyAtomicNumber8()
          {
              int[] results = Match("[#16]", "COC1C(C(C(C(O1)CO)OC2C(C(C(C(O2)CO)S)O)O)O)O");
              Assert.AreEqual(1, results[0]);
              Assert.AreEqual(1, results[1]);
          }
  
          // @cdk.bug 2686473
          [TestMethod()]
          public void TestPropertyAtomicNumber9()
          {
              int[] results = Match("[#6]", "[*]");
              Assert.AreEqual(0, results[0]);
              Assert.AreEqual(0, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyR1()
          {
              int[] results = Match("[R2]", "N12CCC36C1CC(C(C2)=CCOC4CC5=O)C4C3N5c7ccccc76");
              Assert.AreEqual(7, results[0]);
              Assert.AreEqual(7, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyR2()
          {
              SMARTSQueryTool sqt = CreateFromSmarts("[R2]");
              sqt.UseSmallestSetOfSmallestRings(); // default for daylight
              int[] results = Match(sqt, CreateFromSmiles("COc1cc2c(ccnc2cc1)C(O)C4CC(CC3)C(C=C)CN34"));
              Assert.AreEqual(6, results[0]);
              Assert.AreEqual(6, results[1]);
  
          }
  
          [TestMethod(), Ignore()] // This feature was removed - essential rings aren't useful really
          public void TestPropertyR2_essentialRings()
          {
              SMARTSQueryTool sqt = CreateFromSmarts("[R2]");
              sqt.UseEssentialRings();
              int[] results = Match(sqt, CreateFromSmiles("COc1cc2c(ccnc2cc1)C(O)C4CC(CC3)C(C=C)CN34"));
              Assert.AreEqual(2, results[0]);
              Assert.AreEqual(2, results[1]);
          }
  
          [TestMethod(), Ignore()] // This feature is pending but will be the combinded in an 'OpenSMARTS'" + " configuration which uses the relevant rings.
          public void TestPropertyR2_relevantRings()
          {
              SMARTSQueryTool sqt = CreateFromSmarts("[R2]");
              sqt.UseRelevantRings();
              int[] results = Match(sqt, CreateFromSmiles("COc1cc2c(ccnc2cc1)C(O)C4CC(CC3)C(C=C)CN34"));
              Assert.AreEqual(8, results[0]);
              Assert.AreEqual(8, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyR3()
          {
              int[] results = Match("[R2]", "C123C5C(O)C=CC2C(N(C)CC1)Cc(ccc4O)c3c4O5");
              Assert.AreEqual(4, results[0]);
              Assert.AreEqual(4, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyR4()
          {
              int[] results = Match("[R2]", "C123C5C(OC(=O)C)C=CC2C(N(C)CC1)Cc(ccc4OC(=O)C)c3c4O5");
              Assert.AreEqual(4, results[0]);
              Assert.AreEqual(4, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyR5()
          {
              int[] results = Match("[R2]", "C1C(C)=C(C=CC(C)=CC=CC(C)=CCO)C(C)(C)C1");
              Assert.AreEqual(0, results[0]);
              Assert.AreEqual(0, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyr1()
          {
              int[] results = Match("[r5]", "N12CCC36C1CC(C(C2)=CCOC4CC5=O)C4C3N5c7ccccc76");
              Assert.AreEqual(9, results[0]);
              Assert.AreEqual(9, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyr2()
          {
              int[] results = Match("[r5]", "COc1cc2c(ccnc2cc1)C(O)C4CC(CC3)C(C=C)CN34");
              Assert.AreEqual(0, results[0]);
              Assert.AreEqual(0, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyr3()
          {
              int[] results = Match("[r5]", "C123C5C(O)C=CC2C(N(C)CC1)Cc(ccc4O)c3c4O5");
              Assert.AreEqual(5, results[0]);
              Assert.AreEqual(5, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyr4()
          {
              int[] results = Match("[r5]", "C123C5C(OC(=O)C)C=CC2C(N(C)CC1)Cc(ccc4OC(=O)C)c3c4O5");
              Assert.AreEqual(5, results[0]);
              Assert.AreEqual(5, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyr5()
          {
              int[] results = Match("[r5]", "C1C(C)=C(C=CC(C)=CC=CC(C)=CCO)C(C)(C)C1");
              Assert.AreEqual(5, results[0]);
              Assert.AreEqual(5, results[1]);
          }
  
          [TestMethod()]
          public void QuadBond()
          {
              int[] results = Match("*$*", "[Re]$[Re]");
              Assert.AreEqual(2, results[0]);
              Assert.AreEqual(1, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyValence1()
          {
              int[] results = Match("[v4]", "C");
              Assert.AreEqual(1, results[0]);
              Assert.AreEqual(1, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyValence2()
          {
              int[] results = Match("[v4]", "CCO");
              Assert.AreEqual(2, results[0]);
              Assert.AreEqual(2, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyValence3()
          {
              int[] results = Match("[v4]", "[NH4+]");
              Assert.AreEqual(1, results[0]);
              Assert.AreEqual(1, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyValence4()
          {
              int[] results = Match("[v4]", "CC1(C)SC2C(NC(=O)Cc3ccccc3)C(=O)N2C1C(=O)O");
              Assert.AreEqual(16, results[0]);
              Assert.AreEqual(16, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyValence5()
          {
              int[] results = Match("[v4]", "[Cl-].[Cl-].NC(=O)c2cc[n+](COC[n+]1ccccc1C=NO)cc2");
              Assert.AreEqual(16, results[0]);
              Assert.AreEqual(16, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyX1()
          {
              int[] results = Match("[X2]", "CCO");
              Assert.AreEqual(1, results[0]);
              Assert.AreEqual(1, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyX2()
          {
              int[] results = Match("[X2]", "O");
              Assert.AreEqual(1, results[0]);
              Assert.AreEqual(1, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyX3()
          {
              int[] results = Match("[X2]", "CCC(=O)CC");
              Assert.AreEqual(0, results[0]);
              Assert.AreEqual(0, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyX4()
          {
              int[] results = Match("[X2]", "FC(Cl)=C=C(Cl)F");
              Assert.AreEqual(1, results[0]);
              Assert.AreEqual(1, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyX5()
          {
              int[] results = Match("[X2]", "COc1cc2c(ccnc2cc1)C(O)C4CC(CC3)C(C=C)CN34");
              Assert.AreEqual(3, results[0]);
              Assert.AreEqual(3, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyX6()
          {
              int[] results = Match("[X2]", "C123C5C(O)C=CC2C(N(C)CC1)Cc(ccc4O)c3c4O5");
              Assert.AreEqual(3, results[0]);
              Assert.AreEqual(3, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyD1()
          {
              int[] results = Match("[D2]", "CCO");
              Assert.AreEqual(1, results[0]);
          }
  
          [TestMethod()]
          public void TestPropertyD2()
          {
              int[] results = Match("[D2]", "O");
              Assert.AreEqual(0, results[0]);
          }
  
          [TestMethod()]
          public void TestPropertyD3()
          {
              int[] results = Match("[D2]", "CCC(=O)CC");
              Assert.AreEqual(2, results[0]);
          }
  
          [TestMethod()]
          public void TestPropertyD4()
          {
              int[] results = Match("[D2]", "FC(Cl)=C=C(Cl)F");
              Assert.AreEqual(1, results[0]);
          }
  
          [TestMethod()]
          public void TestPropertyD5()
          {
              int[] results = Match("[D2]", "COc1cc2c(ccnc2cc1)C(O)C4CC(CC3)C(C=C)CN34");
              Assert.AreEqual(12, results[0]);
          }
  
          [TestMethod()]
          public void TestPropertyD6()
          {
              int[] results = Match("[D2]", "C123C5C(O)C=CC2C(N(C)CC1)Cc(ccc4O)c3c4O5");
              Assert.AreEqual(8, results[0]);
          }
  
          // @cdk.bug 2489417
          [TestMethod()]
          public void TestPropertyD7()
          {
              int[] results = Match("[ND3]", "CCN([H])([H])");
              Assert.AreEqual(0, results[0]);
              Assert.AreEqual(0, results[1]);
          }
  
          // @cdk.bug 2489417
          [TestMethod()]
          public void TestPropertyD8()
          {
              int[] results = Match("[OD1]", "CO[H]");
              Assert.AreEqual(1, results[0]);
              Assert.AreEqual(1, results[1]);
          }
  
          // @cdk.bug 2489417
          [TestMethod()]
          public void TestPropertyD9()
          {
              int[] results;
  
              results = Match("[OD1H]", "CO");
              Assert.AreEqual(1, results[0]);
              Assert.AreEqual(1, results[1]);
          }
  
          // @cdk.bug 2489417
          [TestMethod()]
          public void TestPropertyD10()
          {
              int[] results;
  
              results = Match("[OD1H]", "CO[H]");
              Assert.AreEqual(1, results[0]);
              Assert.AreEqual(1, results[1]);
          }
  
          // @cdk.bug 2489417
          [TestMethod()]
          public void TestPropertyD11()
          {
              int[] results;
  
              results = Match("[OD1H]-*", "CCO");
              Assert.AreEqual(1, results[0]);
              Assert.AreEqual(1, results[1]);
          }
  
          /// <summary>
          /// With '*' matching 'H', this smarts matches twice 'OC' and 'O[H]'.
          /// </summary>
          // @cdk.bug 2489417
          [TestMethod()]
          public void TestPropertyD12()
          {
              int[] results;
  
              results = Match("[OD1H]-*", "CCO[H]");
              Assert.AreEqual(2, results[0]);
              Assert.AreEqual(2, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyHAtom1()
          {
              int[] results = Match("[H]", "[H+].[Cl-]");
              Assert.AreEqual(1, results[0]);
              Assert.AreEqual(1, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyHAtom2()
          {
              int[] results = Match("[H]", "[2H]");
              Assert.AreEqual(0, results[0]);
              Assert.AreEqual(0, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyHAtom3()
          {
              int[] results = Match("[H]", "[H][H]");
              Assert.AreEqual(2, results[0]);
              Assert.AreEqual(2, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyHAtom4()
          {
              int[] results = Match("[H]", "[CH4]");
              Assert.AreEqual(0, results[0]);
              Assert.AreEqual(0, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyHAtom5()
          {
              int[] results = Match("[H]", "[H]C([H])([H])[H]");
              Assert.AreEqual(4, results[0]);
              Assert.AreEqual(4, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyHTotal1()
          {
              int[] results = Match("[H1]", "CCO");
              Assert.AreEqual(1, results[0]);
              Assert.AreEqual(1, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyHTotal2()
          {
              int[] results = Match("[H1]", "[2H]C#C");
              Assert.AreEqual(2, results[0]);
              Assert.AreEqual(2, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyHTotal3()
          {
              int[] results = Match("[H1]", "[H]C(C)(C)C");
              Assert.AreEqual(1, results[0]);
              Assert.AreEqual(1, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyHTotal4()
          {
              int[] results = Match("[H1]", "COc1cc2c(ccnc2cc1)C(O)C4CC(CC3)C(C=C)CN34");
              Assert.AreEqual(11, results[0]);
              Assert.AreEqual(11, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyHTotal5()
          {
              int[] results = Match("[H1]", "C123C5C(O)C=CC2C(N(C)CC1)Cc(ccc4O)c3c4O5");
              Assert.AreEqual(10, results[0]);
              Assert.AreEqual(10, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyHTotal6()
          {
              int[] results = Match("[H1]", "[H][H]");
              Assert.AreEqual(2, results[0]);
              Assert.AreEqual(2, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAnyAtom1()
          {
              int[] results = Match("[*]", "C");
              Assert.AreEqual(1, results[0]);
              Assert.AreEqual(1, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAnyAtom2()
          {
              int[] results = Match("[*]", "[2H]C");
              Assert.AreEqual(2, results[0]);
              Assert.AreEqual(2, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAnyAtom3()
          {
              int[] results = Match("[*]", "[1H][1H]");
              Assert.AreEqual(2, results[0]);
              Assert.AreEqual(2, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAnyAtom4()
          {
              int[] results = Match("[*]", "[1H]C([1H])([1H])[1H]");
              Assert.AreEqual(5, results[0]);
              Assert.AreEqual(5, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAnyAtom5()
          {
              int[] results = Match("[*]", "[H][H]");
              Assert.AreEqual(2, results[0]);
              Assert.AreEqual(2, results[1]);
          }
  
          /// <summary>
          // @throws Exception
          // @cdk.bug 2489533
          /// </summary>
          [TestMethod()]
          public void TestPropertyAnyAtom6()
          {
              int[] result = Match("*", "CO");
              Assert.AreEqual(2, result[0]);
              Assert.AreEqual(2, result[1]);
          }
  
          /// <summary>
          /// Bug was mistaken - '*' does match explicit H but in DEPICTMATCH H's are
          /// suppressed by default.
          /// </summary>
          // @cdk.bug 2489533
          [TestMethod()]
          public void TestPropertyAnyAtom7()
          {
              int[] result = Match("*", "CO[H]");
              Assert.AreEqual(3, result[0]);
              Assert.AreEqual(3, result[1]);
          }
  
          /// <summary>
          /// Bug was mistaken - '*' does match explicit H but in DEPICTMATCH H's are
          /// suppressed by default.
          /// </summary>
          // @cdk.bug 2489533
          [TestMethod()]
          public void TestPropertyAnyAtom8()
          {
              int[] result = Match("*", "[H]C([H])([H])[H]");
              Assert.AreEqual(5, result[0]);
              Assert.AreEqual(5, result[1]);
          }
  
          /// <summary>
          /// Bug was mistaken - '*' does match explicit H but in DEPICTMATCH H's are
          /// suppressed by default.
          /// </summary>
          // @cdk.bug 2489533
          [TestMethod()]
          public void TestPropertyAnyAtom9()
          {
              int[] result = Match("*", "CCCC([2H])[H]");
              Assert.AreEqual(6, result[0]);
              Assert.AreEqual(6, result[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAtomicMass1()
          {
              int[] results = Match("[13C]", "[13C]");
              Assert.AreEqual(1, results[0]);
              Assert.AreEqual(1, results[1]);
          }
  
          [TestMethod()]
          public void TestPropertyAtomicMass2()
          {
  
gt:             int[] results = Match("[13C]", "[C]");