// // // Copyright (C) 2019 Greg Landrum // // @@ All Rights Reserved @@ // This file is part of the RDKit. // The contents are covered by the terms of the BSD license // which is included in the file license.txt, found at the root // of the RDKit source tree. // const assert = require('assert'); const { performance } = require('perf_hooks'); // the default path to RDKit_minimal.js can be overridden through // the RDKIT_MINIMAL_JS variable if needed const minimalLib = process.env.RDKIT_MINIMAL_JS || '../demo/RDKit_minimal.js'; console.log('Loading ' + minimalLib); var initRDKitModule = require(minimalLib); var RDKitModule; const fs = require('fs'); const readline = require('readline'); const extractBondCoords = (svg, bondDetail) => { const getStartEndCoords = (bond) => { const m = bond.match(/^.*\s+d='M\s+([^,]+),([^ ]+)\s+L\s+([^,]+),([^ ]+)'.*$/); return [[m[1], m[2]], [m[3], m[4]]]; }; const bond = svg.split('\n').filter(line => line.includes(bondDetail)); assert.equal(bond.length, 1); return getStartEndCoords(bond[0]); } const angleDegBetweenVectors = (v1, v2) => 180 / Math.PI * Math.acos((v1[0] * v2[0] + v1[1] * v2[1]) / Math.sqrt((v1[0] * v1[0] + v1[1] * v1[1]) * (v2[0] * v2[0] + v2[1] * v2[1]))); // the goal here isn't to be comprehensive (the RDKit has tests for that), // just to make sure that the wrappers are working as expected function test_basics() { var bmol = null; try { bmol = RDKitModule.get_mol("c1ccccc"); assert(bmol === null); } catch { assert(bmol === null); } var mol = RDKitModule.get_mol("c1ccccc1O"); assert(mol !== null); assert.equal(mol.get_smiles(),"Oc1ccccc1"); if (typeof Object.getPrototypeOf(mol).get_inchi === 'function') { assert.equal(mol.get_inchi(),"InChI=1S/C6H6O/c7-6-4-2-1-3-5-6/h1-5,7H"); assert.equal(mol.get_inchi("-FixedH"),"InChI=1/C6H6O/c7-6-4-2-1-3-5-6/h1-5,7H"); } if (typeof RDKitModule.get_inchikey_for_inchi === 'function') { assert.equal(RDKitModule.get_inchikey_for_inchi(mol.get_inchi("-FixedH")),"ISWSIDIOOBJBQZ-UHFFFAOYNA-N"); assert.equal(RDKitModule.get_inchikey_for_inchi(mol.get_inchi()),"ISWSIDIOOBJBQZ-UHFFFAOYSA-N"); } var mb = mol.get_molblock(); assert(mb.search("M END")>0); var mol2 = RDKitModule.get_mol(mb); assert(mol2 !== null); assert.equal(mol2.get_smiles(),"Oc1ccccc1"); var mjson = mol.get_json(); assert(mjson.search("rdkitjson")>0); var mol3 = RDKitModule.get_mol(mjson); assert(mol3 !== null); assert.equal(mol3.get_smiles(),"Oc1ccccc1"); var descrs = JSON.parse(mol.get_descriptors()); assert.equal(descrs.NumAromaticRings,1); assert.equal(descrs.NumRings,1); assert.equal(descrs.amw,94.11299999999999); var checkStringBinaryFpIdentity = (stringFp, binaryFp) => { assert.equal(binaryFp.length, Math.ceil(stringFp.length / 8)); for (var i = 0, c = 0; i < binaryFp.length; ++i) { var byte = 0; for (var j = 0; j < 8; ++j, ++c) { if (stringFp[c] === "1") { byte |= (1 << j); } } assert.equal(byte, binaryFp[i]); } }; { var fp1 = mol.get_morgan_fp(); assert.equal(fp1.length, 2048); assert.equal((fp1.match(/1/g)||[]).length, 11); var fp1Uint8Array = mol.get_morgan_fp_as_uint8array(); checkStringBinaryFpIdentity(fp1, fp1Uint8Array); var fp2 = mol.get_morgan_fp(JSON.stringify({ radius: 0, nBits: 512 })); assert.equal(fp2.length, 512); assert.equal((fp2.match(/1/g)||[]).length, 3); var fp2Uint8Array = mol.get_morgan_fp_as_uint8array(JSON.stringify({ radius: 0, nBits: 512 })); checkStringBinaryFpIdentity(fp2, fp2Uint8Array); } { var fp1 = mol.get_pattern_fp(); assert.equal(fp1.length, 2048); assert.equal((fp1.match(/1/g)||[]).length, 73); var fp1Uint8Array = mol.get_pattern_fp_as_uint8array(); checkStringBinaryFpIdentity(fp1, fp1Uint8Array); var fp2 = mol.get_pattern_fp(JSON.stringify({ nBits: 256 })); assert.equal(fp2.length, 256); assert.equal((fp2.match(/1/g)||[]).length, 65); var fp2Uint8Array = mol.get_pattern_fp_as_uint8array(JSON.stringify({ nBits: 256 })); checkStringBinaryFpIdentity(fp2, fp2Uint8Array); } { var fp1 = mol.get_topological_torsion_fp(); assert.equal(fp1.length, 2048); assert.equal((fp1.match(/1/g)||[]).length, 8); var fp1Uint8Array = mol.get_topological_torsion_fp_as_uint8array(); checkStringBinaryFpIdentity(fp1, fp1Uint8Array); var fp2 = mol.get_topological_torsion_fp(JSON.stringify({ nBits: 512 })); assert.equal(fp2.length, 512); assert.equal((fp2.match(/1/g)||[]).length, 8); var fp2Uint8Array = mol.get_topological_torsion_fp_as_uint8array(JSON.stringify({ nBits: 512 })); checkStringBinaryFpIdentity(fp2, fp2Uint8Array); } { var fp1 = mol.get_rdkit_fp(); assert.equal(fp1.length, 2048); assert.equal((fp1.match(/1/g)||[]).length, 38); var fp1Uint8Array = mol.get_rdkit_fp_as_uint8array(); checkStringBinaryFpIdentity(fp1, fp1Uint8Array); var fp2 = mol.get_rdkit_fp(JSON.stringify({ nBits: 512 })); assert.equal(fp2.length, 512); assert.equal((fp2.match(/1/g)||[]).length, 37); var fp2Uint8Array = mol.get_rdkit_fp_as_uint8array(JSON.stringify({ nBits: 512 })); checkStringBinaryFpIdentity(fp2, fp2Uint8Array); var fp3 = mol.get_rdkit_fp(JSON.stringify({ nBits: 512, minPath: 2 })); assert.equal(fp3.length, 512); assert.equal((fp3.match(/1/g)||[]).length, 34); var fp3Uint8Array = mol.get_rdkit_fp_as_uint8array(JSON.stringify({ nBits: 512, minPath: 2 })); checkStringBinaryFpIdentity(fp3, fp3Uint8Array); var fp4 = mol.get_rdkit_fp(JSON.stringify({ nBits: 512, minPath: 2, maxPath: 4 })); assert.equal(fp4.length, 512); assert.equal((fp4.match(/1/g)||[]).length, 16); var fp4Uint8Array = mol.get_rdkit_fp_as_uint8array(JSON.stringify({ nBits: 512, minPath: 2, maxPath: 4 })); checkStringBinaryFpIdentity(fp4, fp4Uint8Array); } { var fp1 = mol.get_atom_pair_fp(); assert.equal(fp1.length, 2048); assert.equal((fp1.match(/1/g)||[]).length, 19); var fp1Uint8Array = mol.get_atom_pair_fp_as_uint8array(); checkStringBinaryFpIdentity(fp1, fp1Uint8Array); var fp2 = mol.get_atom_pair_fp(JSON.stringify({ nBits: 512 })); assert.equal(fp2.length, 512); assert.equal((fp2.match(/1/g)||[]).length, 19); var fp2Uint8Array = mol.get_atom_pair_fp_as_uint8array(JSON.stringify({ nBits: 512 })); checkStringBinaryFpIdentity(fp2, fp2Uint8Array); var fp3 = mol.get_atom_pair_fp(JSON.stringify({ nBits: 512, minLength: 2 })); assert.equal(fp3.length, 512); assert.equal((fp3.match(/1/g)||[]).length, 13); var fp3Uint8Array = mol.get_atom_pair_fp_as_uint8array(JSON.stringify({ nBits: 512, minLength: 2 })); checkStringBinaryFpIdentity(fp3, fp3Uint8Array); var fp4 = mol.get_atom_pair_fp(JSON.stringify({ nBits: 512, minLength: 2, maxLength: 3 })); assert.equal(fp4.length, 512); assert.equal((fp4.match(/1/g)||[]).length, 12); var fp4Uint8Array = mol.get_atom_pair_fp_as_uint8array(JSON.stringify({ nBits: 512, minLength: 2, maxLength: 3 })); checkStringBinaryFpIdentity(fp4, fp4Uint8Array); } { var fp1 = mol.get_maccs_fp(); assert.equal(fp1.length, 167); assert.equal((fp1.match(/1/g)||[]).length, 10); var fp1Uint8Array = mol.get_maccs_fp_as_uint8array(); checkStringBinaryFpIdentity(fp1, fp1Uint8Array); } if (typeof Object.getPrototypeOf(mol).get_avalon_fp === 'function') { var fp1 = mol.get_avalon_fp(); assert.equal(fp1.length, 512); assert.equal((fp1.match(/1/g)||[]).length, 19); var fp1Uint8Array = mol.get_avalon_fp_as_uint8array(); checkStringBinaryFpIdentity(fp1, fp1Uint8Array); var fp2 = mol.get_avalon_fp(JSON.stringify({ nBits: 2048 })); assert.equal(fp2.length, 2048); assert.equal((fp2.match(/1/g)||[]).length, 20); var fp2Uint8Array = mol.get_avalon_fp_as_uint8array(JSON.stringify({ nBits: 2048 })); checkStringBinaryFpIdentity(fp2, fp2Uint8Array); } var svg = mol.get_svg(); assert(svg.search("svg")>0); var qmol = RDKitModule.get_qmol("Oc(c)c"); assert(qmol !== null); var match = mol.get_substruct_match(qmol); var pmatch = JSON.parse(match); assert.equal(pmatch.atoms.length,4); assert.equal(pmatch.atoms[0],6); var svg2 = mol.get_svg_with_highlights(match); assert(svg2.search("svg")>0); assert(svg.search("#FF7F7F")<0); assert(svg2.search("#FF7F7F")>0); } function test_molblock_nostrict() { var molblock = ` MJ201100 10 10 0 0 0 0 0 0 0 0999 V2000 -1.2946 0.5348 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.0090 0.1223 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.0090 -0.7027 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.2946 -1.1152 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.5801 -0.7027 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.5801 0.1223 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.5467 1.2493 0.0000 F 0 0 0 0 0 0 0 0 0 0 0 0 0.1342 0.5348 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.5467 -0.1796 0.0000 F 0 0 0 0 0 0 0 0 0 0 0 0 -0.6907 0.5348 0.0000 F 0 0 0 0 0 0 0 0 0 0 0 0 1 2 2 0 0 0 0 2 3 1 0 0 0 0 3 4 2 0 0 0 0 4 5 1 0 0 0 0 5 6 2 0 0 0 0 6 1 1 0 0 0 0 6 8 1 0 0 0 0 7 8 1 0 0 0 0 8 9 1 0 0 0 0 8 10 1 0 0 0 0 M STY 1 1 SUP M SAL 1 4 7 8 9 10 M SMT 1 CF3 M SBL 1 1 7 M SAP 1 1 8 M END`; var mol = RDKitModule.get_mol(molblock); assert(mol !== null); var mb = mol.get_molblock(); assert.equal(mb.includes("M SAP 1 1 8 6"), true); var qmol = RDKitModule.get_qmol(molblock); assert(qmol !== null); var qmb = qmol.get_molblock(); assert.equal(qmb.includes("M SAP 1 1 8 6"), true); } function test_molblock_rgp() { var molblock = ` MJ190400 9 9 0 0 0 0 0 0 0 0999 V2000 -6.5623 0.3105 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0 -5.8478 -0.1019 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -5.1333 0.3105 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 -4.4188 -0.1019 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 -4.4188 -0.9269 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -5.1333 -1.3394 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -5.8478 -0.9269 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -3.7043 -1.3394 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 -2.9898 -0.9268 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0 3 4 4 0 0 0 0 4 5 4 0 0 0 0 5 6 4 0 0 0 0 6 7 4 0 0 0 0 2 3 4 0 0 0 0 2 7 4 0 0 0 0 5 8 1 0 0 0 0 8 9 1 0 0 0 0 1 2 1 0 0 0 0 M RGP 2 1 2 9 1 M END`; var mol = RDKitModule.get_mol(molblock); assert(mol !== null); } function test_get_aromatic_kekule_form() { const aromRegExp = / \d \d 4 \d\n/g; const kekRegExp = / \d \d [12] \d\n/g; var mol = RDKitModule.get_mol("c1ccccc1"); var molblock = mol.get_molblock(); assert (molblock.match(aromRegExp) === null); assert (molblock.match(kekRegExp).length === 6); var molblock = mol.get_kekule_form(); assert (molblock.match(aromRegExp) === null); assert (molblock.match(kekRegExp).length === 6); molblock = mol.get_aromatic_form(); assert (molblock.match(aromRegExp).length === 6); assert (molblock.match(kekRegExp) === null); mol.delete(); mol = RDKitModule.get_qmol(` MJ201100 6 6 0 0 0 0 0 0 0 0999 V2000 -0.6473 0.8696 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.3617 0.4571 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.3617 -0.3679 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.6473 -0.7804 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.0671 -0.3679 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.0671 0.4571 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1 2 4 0 0 0 0 2 3 4 0 0 0 0 3 4 4 0 0 0 0 4 5 4 0 0 0 0 5 6 4 0 0 0 0 6 1 4 0 0 0 0 M END `); molblock = mol.get_aromatic_form(); assert (molblock.match(aromRegExp).length === 6); assert (molblock.match(kekRegExp) === null); molblock = mol.get_kekule_form(); assert (molblock.match(aromRegExp) === null); assert (molblock.match(kekRegExp).length === 6); mol.delete(); mol = RDKitModule.get_qmol(` MJ201100 6 6 0 0 0 0 0 0 0 0999 V2000 -0.6473 0.8696 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.3617 0.4571 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.3617 -0.3679 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.6473 -0.7804 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.0671 -0.3679 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.0671 0.4571 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1 2 2 0 0 0 0 2 3 1 0 0 0 0 3 4 2 0 0 0 0 4 5 1 0 0 0 0 5 6 2 0 0 0 0 6 1 1 0 0 0 0 M END `); molblock = mol.get_molblock(JSON.stringify({ kekulize: false })); assert (molblock.match(aromRegExp) === null); assert (molblock.match(kekRegExp).length === 6); mol.convert_to_aromatic_form(); molblock = mol.get_molblock(JSON.stringify({ kekulize: false })); assert (molblock.match(aromRegExp).length === 6); assert (molblock.match(kekRegExp) === null); mol.convert_to_kekule_form(); molblock = mol.get_molblock(JSON.stringify({ kekulize: false })); assert (molblock.match(aromRegExp) === null); assert (molblock.match(kekRegExp).length === 6); mol.delete(); } function test_sketcher_services() { var mol = RDKitModule.get_mol("C[C@](F)(Cl)/C=C/C(F)Br"); assert(mol !== null); var tags = mol.get_stereo_tags(); assert.equal(tags,'{"CIP_atoms":[[1,"(S)"],[6,"(?)"]],"CIP_bonds":[[4,5,"(E)"]]}'); } function test_sketcher_services2() { var mol = RDKitModule.get_mol("c1ccccc1"); assert(mol !== null); var molb = mol.add_hs(); assert(molb.search(" H ")>0); assert.equal((molb.match(/ H /g) || []).length,6); var mol2 = RDKitModule.get_mol(molb); assert(mol2 !== null); var molb2 = mol2.get_molblock(); assert(molb2.search(" H ")>0); assert.equal((molb2.match(/ H /g) || []).length,6); molb2 = mol2.remove_hs(); assert(molb2.search(" H ")<0); } function test_abbreviations() { var bmol = RDKitModule.get_mol("C1CC(C(F)(F)F)C1"); assert(bmol !== null); var mapping = bmol.condense_abbreviations(); assert.equal(mapping, JSON.stringify({ atoms: [0, 1, 2, 3, 4, 5, 6, 7], bonds: [0, 1, 2, 3, 4, 5, 6, 7], })); assert.equal(bmol.get_cxsmiles(),"FC(F)(F)C1CCC1"); mapping = bmol.condense_abbreviations(1.0,false); assert.equal(mapping, JSON.stringify({ atoms: [0, 1, 2, 3, 7], bonds: [0, 1, 2, 6, 7], })); assert.equal(bmol.get_cxsmiles(),"*C1CCC1 |$CF3;;;;$|"); } function test_substruct_library(done) { done.test_substruct_library = false; var query = RDKitModule.get_qmol('C1CCCCN1'); var nonExistingQuery = RDKitModule.get_mol('O=C(O)C(c1ccc(cc1)CCN4CCC(c2nc3ccccc3n2CCOCC)CC4)(C)C'); const numBitOptions = [-1, 0]; var patternFpArray = []; var sslibObjs = []; numBitOptions.forEach((numBits, optIdx) => { var smiReader = readline.createInterface({ input: fs.createReadStream(__dirname + '/../../GraphMol/test_data/compounds.smi') }); var sslib = numBits < 0 ? new RDKitModule.SubstructLibrary() : new RDKitModule.SubstructLibrary(numBits); assert(sslib); sslibObjs.push(sslib); assert.equal(sslib.count_matches(query), 0); assert.equal(sslib.get_matches(query), JSON.stringify([])); assert.equal(sslib.get_matches_as_uint32array(query).length, 0); // var t0 = performance.now() // console.log('Started adding trusted SMILES'); var matches = []; var expectedMatches = [39, 64, 80, 127, 128, 234, 240]; var i = 0; var trustedSmiArray = [] smiReader.on('line', (smi) => { sslib.add_trusted_smiles(smi); var mol = RDKitModule.get_mol(smi); var res = JSON.parse(mol.get_substruct_match(query)); if (res.atoms) { matches.push(i); } ++i; mol.delete(); }); smiReader.on('close', () => { // var t1 = performance.now(); // console.log('Finished adding trusted SMILES took ' + (t1 - t0) / 1000 + ' seconds'); for (var i = 0; i < sslib.size(); ++i) { trustedSmiArray.push(sslib.get_trusted_smiles(i)); let excRaised = false; try { var fp = sslib.get_pattern_fp_as_uint8array(i); patternFpArray.push(fp); } catch (e) { // this is expected to fail when numBits === 0 excRaised = true; } assert((excRaised && numBits === 0) || (!excRaised && numBits !== 0)); } assert.equal(trustedSmiArray.length, sslib.size()); assert.equal(patternFpArray.length, sslib.size()); assert.equal(trustedSmiArray.length, patternFpArray.length); var sslib2 = new RDKitModule.SubstructLibrary(); assert(sslib2); sslibObjs.push(sslib2); for (var i = 0; i < sslib.size(); ++i) { sslib2.add_trusted_smiles_and_pattern_fp(trustedSmiArray[i], patternFpArray[i]); } assert.equal(sslib.size(), sslib2.size()); { assert.equal(sslib.count_matches(query, false), 7); var sslibMatches = sslib.get_matches(query); assert.equal(sslibMatches, JSON.stringify(expectedMatches)); assert.equal(sslibMatches, JSON.stringify(matches)); var sslibMatchesUInt32Array = sslib.get_matches_as_uint32array(query); assert.equal(sslibMatchesUInt32Array.length, expectedMatches.length); for (var i = 0; i < expectedMatches.length; ++i) { assert.equal(sslibMatchesUInt32Array[i], expectedMatches[i]); } } { assert.equal(sslib.count_matches(nonExistingQuery, false), 0); var sslibMatches = sslib.get_matches(nonExistingQuery); assert.equal(sslibMatches, JSON.stringify([])); var sslibMatchesUInt32Array = sslib.get_matches_as_uint32array(nonExistingQuery); assert.equal(sslibMatchesUInt32Array.length, 0); } { assert.equal(sslib2.count_matches(query, false), 7); var sslib2Matches = sslib2.get_matches(query); assert.equal(sslib2Matches, JSON.stringify(expectedMatches)); assert.equal(sslib2Matches, JSON.stringify(matches)); var sslib2MatchesUInt32Array = sslib2.get_matches_as_uint32array(query); assert.equal(sslib2MatchesUInt32Array.length, expectedMatches.length); for (var i = 0; i < expectedMatches.length; ++i) { assert.equal(sslib2MatchesUInt32Array[i], expectedMatches[i]); } } { assert.equal(sslib2.count_matches(nonExistingQuery, false), 0); var sslib2Matches = sslib2.get_matches(nonExistingQuery); assert.equal(sslib2Matches, JSON.stringify([])); var sslib2MatchesUInt32Array = sslib2.get_matches_as_uint32array(nonExistingQuery); assert.equal(sslib2MatchesUInt32Array.length, 0); } if (optIdx === numBitOptions.length - 1) { done.test_substruct_library = true; query.delete(); nonExistingQuery.delete(); sslibObjs.forEach((sslib) => { sslib.delete(); }); } }); }); } function test_substruct_library_merge_hs() { var sslib = new RDKitModule.SubstructLibrary(); var mol1 = RDKitModule.get_mol("c1ccccc1"); var mol2 = RDKitModule.get_mol("Cc1ccccc1"); sslib.add_trusted_smiles(mol1.get_smiles()); sslib.add_trusted_smiles(mol2.get_smiles()); var query = RDKitModule.get_mol(` MJ201100 2D 6 6 0 0 0 0 0 0 0 0999 V2000 -1.0491 0.7134 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.7635 0.3009 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.7635 -0.5241 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.0491 -0.9366 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.3346 -0.5241 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.3346 0.3009 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2 3 1 0 0 0 0 5 6 2 0 0 0 0 1 2 2 0 0 0 0 6 1 1 0 0 0 0 3 4 2 0 0 0 0 4 5 1 0 0 0 0 M END`); assert.equal(sslib.get_matches(query), JSON.stringify([0, 1])); var query_hs = RDKitModule.get_mol(query.add_hs()); assert.equal(sslib.get_matches(query_hs), JSON.stringify([])); query_hs = RDKitModule.get_mol(query_hs.get_molblock(), JSON.stringify({ mergeQueryHs: true })); assert.equal(sslib.get_matches(query_hs), JSON.stringify([0])); } function test_substruct_library_empty_mols() { var sslib = new RDKitModule.SubstructLibrary(); var mol1 = RDKitModule.get_mol(""); var mol2 = RDKitModule.get_mol(""); sslib.add_trusted_smiles(mol1.get_smiles()); sslib.add_trusted_smiles(mol2.get_smiles()); var query = RDKitModule.get_mol("C"); assert.equal(sslib.get_matches(query), JSON.stringify([])); var empty_query = RDKitModule.get_mol(""); assert.equal(sslib.get_matches(empty_query), JSON.stringify([])); } function test_substruct_library_empty_query() { var sslib = new RDKitModule.SubstructLibrary(); var mol1 = RDKitModule.get_mol("C"); var mol2 = RDKitModule.get_mol("CC"); sslib.add_trusted_smiles(mol1.get_smiles()); sslib.add_trusted_smiles(mol2.get_smiles()); var query = RDKitModule.get_mol(""); assert.equal(sslib.get_matches(query), JSON.stringify([])); } function test_substruct_library_empty_lib() { var sslib = new RDKitModule.SubstructLibrary(); var query = RDKitModule.get_mol("C"); assert.equal(sslib.get_matches(query), JSON.stringify([])); var empty_query = RDKitModule.get_mol(""); assert.equal(sslib.get_matches(empty_query), JSON.stringify([])); } function test_generate_aligned_coords() { var smiles = "CCC"; var mol = RDKitModule.get_mol(smiles); var template = "CC"; var qmol = RDKitModule.get_mol(template); assert.equal(mol.generate_aligned_coords(qmol, JSON.stringify({useCoordGen: true})), ""); } function test_isotope_labels() { var mol = RDKitModule.get_mol("[1*]c1cc([2*])c([3*])c[14c]1"); assert(mol !== null); var textIsoDummyIso = mol.get_svg_with_highlights(JSON.stringify({})); var nLinesIsoDummyIso = textIsoDummyIso.split("\n").length; var textNoIsoDummyIso = mol.get_svg_with_highlights(JSON.stringify({ isotopeLabels: false })); var nLinesNoIsoDummyIso = textNoIsoDummyIso.split("\n").length; var textIsoNoDummyIso = mol.get_svg_with_highlights(JSON.stringify({ dummyIsotopeLabels: false })); var nLinesIsoNoDummyIso = textIsoNoDummyIso.split("\n").length; var textNoIsoNoDummyIso = mol.get_svg_with_highlights(JSON.stringify({ isotopeLabels: false, dummyIsotopeLabels: false })); var nLinesNoIsoNoDummyIso = textNoIsoNoDummyIso.split("\n").length; var res = [nLinesNoIsoNoDummyIso, nLinesIsoNoDummyIso, nLinesNoIsoDummyIso, nLinesIsoDummyIso]; var resSorted = [...res]; resSorted.sort((a, b) => (a - b)); assert.ok(res.every((resItem, i) => (resItem === resSorted[i]))); } function test_generate_aligned_coords_allow_rgroups() { var template_molblock = ` RDKit 2D 9 9 0 0 0 0 0 0 0 0999 V2000 -0.8929 1.0942 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.1919 0.3442 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.1919 -1.1558 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.8929 -1.9059 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.4060 -1.1558 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.4060 0.3442 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -3.4910 1.0942 0.0000 R1 0 0 0 0 0 0 0 0 0 0 0 0 1.7051 1.0942 0.0000 R2 0 0 0 0 0 0 0 0 0 0 0 0 -3.4910 -1.9059 0.0000 R3 0 0 0 0 0 0 0 0 0 0 0 0 1 2 2 0 2 3 1 0 3 4 2 0 4 5 1 0 5 6 2 0 6 1 1 0 6 8 1 0 3 9 1 0 2 7 1 0 M RGP 3 7 1 8 2 9 3 M END`; var ortho_meta_smiles = 'c1ccc(-c2ccc(-c3ccccc3)c(-c3ccccc3)c2)cc1'; var ortho_smiles = 'c1ccc(-c2ccccc2-c2ccccc2)cc1'; var meta_smiles = 'c1ccc(-c2cccc(-c3ccccc3)c2)cc1'; var para_smiles = 'c1ccc(-c2ccc(-c3ccccc3)cc2)cc1'; var biphenyl_smiles = 'c1ccccc1-c1ccccc1'; var phenyl_smiles = 'c1ccccc1'; var template_ref = RDKitModule.get_mol(template_molblock); var ortho_meta = RDKitModule.get_mol(ortho_meta_smiles); var ortho = RDKitModule.get_mol(ortho_smiles); var meta = RDKitModule.get_mol(meta_smiles); var para = RDKitModule.get_mol(para_smiles); var biphenyl = RDKitModule.get_mol(biphenyl_smiles); var phenyl = RDKitModule.get_mol(phenyl_smiles); assert.equal(JSON.parse(ortho_meta.generate_aligned_coords( template_ref, JSON.stringify({ useCoordGen: false, allowRGroups: true}))).atoms.length, 9); [ true, false ].forEach(alignOnly => { var opts = JSON.stringify({ useCoordGen: false, allowRGroups: true, alignOnly }); assert.equal(JSON.parse(ortho_meta.generate_aligned_coords( template_ref, opts)).atoms.length, 9); assert.equal(JSON.parse(ortho.generate_aligned_coords( template_ref, opts)).atoms.length, 8); assert.equal(JSON.parse(meta.generate_aligned_coords( template_ref, opts)).atoms.length, 8); assert.equal(JSON.parse(para.generate_aligned_coords( template_ref, opts)).atoms.length, 8); assert.equal(JSON.parse(biphenyl.generate_aligned_coords( template_ref, opts)).atoms.length, 7); assert.equal(JSON.parse(phenyl.generate_aligned_coords( template_ref, opts)).atoms.length, 6); }); const pyridineRef = RDKitModule.get_mol(` MJ201100 8 8 0 0 0 0 0 0 0 0999 V2000 0.0000 0.8250 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.7144 0.4125 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.7144 -0.4124 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.0000 -0.8250 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.7144 -0.4124 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.7144 0.4125 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 0.0000 1.6500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.0000 -1.6500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1 2 2 0 0 0 0 2 3 1 0 0 0 0 3 4 2 0 0 0 0 4 5 1 0 0 0 0 5 6 2 0 0 0 0 6 1 1 0 0 0 0 1 7 1 0 0 0 0 4 8 1 0 0 0 0 M END `); const referenceSmarts = "[*:3]a1a([*:1])aa([*:2])aa1"; [ true, false ].forEach(alignOnly => { var opts = JSON.stringify({ useCoordGen: false, allowRGroups: true, alignOnly, referenceSmarts }); assert.equal(JSON.parse(ortho_meta.generate_aligned_coords( pyridineRef, opts)).atoms.length, 8); assert.equal(JSON.parse(ortho.generate_aligned_coords( pyridineRef, opts)).atoms.length, 7); assert.equal(JSON.parse(meta.generate_aligned_coords( pyridineRef, opts)).atoms.length, 7); assert.equal(JSON.parse(para.generate_aligned_coords( pyridineRef, opts)).atoms.length, 8); assert.equal(JSON.parse(biphenyl.generate_aligned_coords( pyridineRef, opts)).atoms.length, 7); assert.equal(JSON.parse(phenyl.generate_aligned_coords( pyridineRef, opts)).atoms.length, 6); }); } function test_generate_aligned_coords_accept_failure() { var template_molblock = ` RDKit 2D 9 9 0 0 0 0 0 0 0 0999 V2000 -0.8929 1.0942 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.1919 0.3442 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.1919 -1.1558 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.8929 -1.9059 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.4060 -1.1558 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.4060 0.3442 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -3.4910 1.0942 0.0000 R1 0 0 0 0 0 0 0 0 0 0 0 0 1.7051 1.0942 0.0000 R2 0 0 0 0 0 0 0 0 0 0 0 0 -3.4910 -1.9059 0.0000 R3 0 0 0 0 0 0 0 0 0 0 0 0 1 2 2 0 2 3 1 0 3 4 2 0 4 5 1 0 5 6 2 0 6 1 1 0 6 8 1 0 3 9 1 0 2 7 1 0 M RGP 3 7 1 8 2 9 3 M END `; var mol_molblock = ` RDKit 2D 9 9 0 0 0 0 0 0 0 0999 V2000 -0.8929 1.0942 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 -2.1919 0.3442 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.1919 -1.1558 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.8929 -1.9059 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.4060 -1.1558 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.4060 0.3442 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -3.4910 1.0942 0.0000 F 0 0 0 0 0 0 0 0 0 0 0 0 1.7051 1.0942 0.0000 Cl 0 0 0 0 0 0 0 0 0 0 0 0 -3.4910 -1.9059 0.0000 Br 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 0 2 3 2 0 3 4 1 0 4 5 2 0 5 6 1 0 6 1 2 0 6 8 1 0 3 9 1 0 2 7 1 0 M END `; var template_ref = RDKitModule.get_mol(template_molblock); var mol = RDKitModule.get_mol(mol_molblock); var res = mol.generate_aligned_coords(template_ref, JSON.stringify({ useCoordGen: false, allowRGroups: true, acceptFailure: false })); assert(res === ""); assert.equal(mol.get_molblock(), mol_molblock); res = mol.generate_aligned_coords(template_ref, JSON.stringify({ useCoordGen: false, allowRGroups: true, acceptFailure: true, })); assert(res === "{}"); assert.notEqual(mol.get_molblock(), mol_molblock); var molNoCoords = RDKitModule.get_mol(mol.get_smiles()); assert(!molNoCoords.has_coords()); res = molNoCoords.generate_aligned_coords(template_ref, JSON.stringify({ useCoordGen: false, allowRGroups: true, acceptFailure: false, })); assert(res === ""); assert(!molNoCoords.has_coords()); res = molNoCoords.generate_aligned_coords(template_ref, JSON.stringify({ useCoordGen: false, allowRGroups: true, acceptFailure: true, })); assert(res === "{}"); assert(molNoCoords.has_coords()); } function test_generate_aligned_coords_align_only() { const template_molblock = ` RDKit 2D 6 6 0 0 0 0 0 0 0 0999 V2000 -13.7477 6.3036 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0 -13.7477 4.7567 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -12.6540 3.6628 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -13.7477 2.5691 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -14.8414 3.6628 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 -11.1071 3.6628 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 0 2 3 1 0 3 4 1 0 4 5 1 0 2 5 1 0 3 6 1 0 M RGP 2 1 1 6 2 M END `; const mol_molblock = ` RDKit 2D 18 22 0 0 0 0 0 0 0 0999 V2000 4.3922 -1.5699 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.9211 -2.0479 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.5995 -0.5349 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 3.3731 0.8046 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 4.8441 1.2825 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 4.0704 -0.0568 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1.8666 0.7748 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 0.7736 -0.3197 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.7749 -1.8666 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.7718 -1.8679 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 -0.7731 -0.3208 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.8679 0.7718 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 -4.0718 -0.0598 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -4.3933 -1.5729 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.9222 -2.0509 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.6008 -0.5379 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -3.3744 0.8016 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -4.8454 1.2795 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 9 10 1 0 11 10 1 0 11 8 1 0 8 9 1 0 4 5 1 0 6 5 1 0 7 6 1 0 3 4 1 0 3 7 1 0 1 6 1 0 2 3 1 0 2 1 1 0 17 18 1 0 13 18 1 0 12 13 1 0 16 17 1 0 16 12 1 0 14 13 1 0 15 16 1 0 15 14 1 0 12 11 1 0 8 7 1 0 M END `; const getCoordArray = (mol) => { const molblock = mol.get_molblock().split("\n"); const numHeavyAtoms = parseInt(molblock[3].substr(0, 3)); return molblock.filter((_, idx) => idx > 3 && idx < 4 + numHeavyAtoms).map( line => [0, 1, 2].map(i => parseFloat(line.substr(i * 10, (i + 1) * 10))) ); }; const arraySum = (a) => { const s = 0.; return a.reduce((prev, curr) => prev + curr, s); }; const sqDist = (xyz1, xyz2) => arraySum(xyz1.map((c, i) => (c - xyz2[i]) * (c - xyz2[i]))) const template_ref = RDKitModule.get_mol(template_molblock); const mol = RDKitModule.get_mol(mol_molblock); const molCoords = getCoordArray(mol); const bondLength11_12 = Math.sqrt(sqDist(molCoords[11], molCoords[12])); const bondLength5_6 = Math.sqrt(sqDist(molCoords[5], molCoords[6])); assert(Math.abs(bondLength11_12 - bondLength5_6) < 1.e-4); assert(bondLength11_12 > 2.3); [ false, true ].forEach(alignOnly => { const mol = RDKitModule.get_mol(mol_molblock); const res = JSON.parse(mol.generate_aligned_coords(template_ref, JSON.stringify({ allowRGroups: true, alignOnly }))); assert([ 11, 10, 7, 8, 9, 6 ].every((idx, i) => res.atoms[i] === idx)); assert(mol.get_smiles() === "C1CC2CCC1N2C1CNC1N1C2CCC1CC2"); const molAliCoords = getCoordArray(mol); const templateCoords = getCoordArray(template_ref); res.atoms.forEach((molIdx, templateIdx) => { assert(sqDist(molAliCoords[molIdx], templateCoords[templateIdx]) < 1.e-4); }); const bondLengthAli11_12 = Math.sqrt(sqDist(molAliCoords[11], molAliCoords[12])); const bondLengthAli5_6 = Math.sqrt(sqDist(molAliCoords[5], molAliCoords[6])); assert(Math.abs(bondLengthAli11_12 - bondLengthAli5_6) < 1.e-4); if (alignOnly) { assert(bondLengthAli11_12 > 2.3); } else { assert(bondLengthAli11_12 < 1.6); } }); } function test_get_mol_no_kekulize() { var molIsValid = true; try { mol = RDKitModule.get_mol("c"); molIsValid = (mol !== null); } catch (e) { molIsValid = false; } assert(!molIsValid); mol = RDKitModule.get_mol("c", JSON.stringify({kekulize: false})); assert(mol !== null); } function test_get_smarts() { var mol = RDKitModule.get_mol(` MJ201100 8 8 0 0 0 0 0 0 0 0999 V2000 -1.0491 1.5839 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.7635 1.1714 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.7635 0.3463 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.0491 -0.0661 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.3346 0.3463 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.3346 1.1714 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.3798 1.5839 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0 0.3798 -0.0661 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0 1 2 2 0 0 0 0 2 3 1 0 0 0 0 3 4 2 0 0 0 0 4 5 1 0 0 0 0 5 6 2 0 0 0 0 6 1 1 0 0 0 0 6 7 1 0 0 2 0 5 8 1 0 0 2 0 M RGP 2 7 1 8 2 M END `); assert(mol !== null); smarts = mol.get_smarts(); assert(smarts == "[#6]1:[#6]:[#6]:[#6]:[#6](:[#6]:1-&!@*)-&!@*"); } function test_get_cxsmarts() { var mol = RDKitModule.get_mol(` MJ201100 8 8 0 0 0 0 0 0 0 0999 V2000 -1.0491 1.5839 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.7635 1.1714 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.7635 0.3463 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.0491 -0.0661 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.3346 0.3463 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.3346 1.1714 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.3798 1.5839 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0 0.3798 -0.0661 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0 1 2 2 0 0 0 0 2 3 1 0 0 0 0 3 4 2 0 0 0 0 4 5 1 0 0 0 0 5 6 2 0 0 0 0 6 1 1 0 0 0 0 6 7 1 0 0 2 0 5 8 1 0 0 2 0 M RGP 2 7 1 8 2 M END `); assert(mol !== null); cxsmarts = mol.get_cxsmarts(); assert(cxsmarts == "[#6]1:[#6]:[#6]:[#6]:[#6](:[#6]:1-&!@*)-&!@* |" + "(-1.0491,1.5839,;-1.7635,1.1714,;-1.7635,0.3463,;-1.0491,-0.0661,;" + "-0.3346,0.3463,;-0.3346,1.1714,;0.3798,1.5839,;0.3798,-0.0661,)," + "atomProp:6.dummyLabel.R1:7.dummyLabel.R2|"); } function test_normalize_depiction() { var mol = RDKitModule.get_mol(` MJ201100 9 10 0 0 0 0 0 0 0 0999 V2000 -1.5402 1.3161 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.2546 0.9036 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.2546 0.0785 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.5402 -0.3339 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.8257 0.0785 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.8257 0.9036 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.0411 -0.1764 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 0.4438 0.4909 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.0410 1.1583 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1 2 2 0 0 0 0 2 3 1 0 0 0 0 3 4 2 0 0 0 0 4 5 1 0 0 0 0 5 6 2 0 0 0 0 6 1 1 0 0 0 0 8 9 2 0 0 0 0 6 9 1 0 0 0 0 7 8 1 0 0 0 0 5 7 1 0 0 0 0 M END `); const scalingFactor = mol.normalize_depiction(); assert(scalingFactor > 1.8 && scalingFactor < 1.9); } function test_straighten_depiction() { var benzeneHoriz = RDKitModule.get_mol(` MJ201100 6 6 0 0 0 0 0 0 0 0999 V2000 -0.0785 1.6073 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.9035 1.6073 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.3160 0.8928 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.9036 0.1783 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.0786 0.1783 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.3339 0.8929 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1 2 2 0 0 0 0 2 3 1 0 0 0 0 3 4 2 0 0 0 0 4 5 1 0 0 0 0 5 6 2 0 0 0 0 6 1 1 0 0 0 0 M END `); var benzeneVert = RDKitModule.get_mol(` MJ201100 6 6 0 0 0 0 0 0 0 0999 V2000 0.2234 1.3054 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.4910 1.7178 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.2055 1.3053 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.2056 0.4803 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.4911 0.0678 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.2234 0.4804 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1 2 2 0 0 0 0 2 3 1 0 0 0 0 3 4 2 0 0 0 0 4 5 1 0 0 0 0 5 6 2 0 0 0 0 6 1 1 0 0 0 0 M END `); var benzeneHorizCopy = RDKitModule.get_mol_copy(benzeneHoriz); var benzeneVertCopy = RDKitModule.get_mol_copy(benzeneVert); benzeneHoriz.straighten_depiction(); benzeneVert.straighten_depiction(); assert(benzeneHoriz.get_molblock() !== benzeneHorizCopy.get_molblock()); assert(benzeneVert.get_molblock() === benzeneVertCopy.get_molblock()); benzeneHoriz = benzeneHorizCopy; benzeneVert = benzeneVertCopy; benzeneHorizCopy = RDKitModule.get_mol_copy(benzeneHoriz); benzeneVertCopy = RDKitModule.get_mol_copy(benzeneVert); benzeneHoriz.straighten_depiction(true); benzeneVert.straighten_depiction(true); assert(benzeneHoriz.get_molblock() === benzeneHorizCopy.get_molblock()); assert(benzeneVert.get_molblock() === benzeneVertCopy.get_molblock()); } function test_has_coords() { var mol = RDKitModule.get_mol('CC'); assert(!mol.has_coords()); var mol2 = RDKitModule.get_mol(mol.get_new_coords()); assert.equal(mol2.has_coords(), 2); assert(!mol.has_coords()); mol.set_new_coords(); assert.equal(mol.has_coords(), 2); var mol3 = RDKitModule.get_mol(` RDKit 3D 9 9 0 0 0 0 0 0 0 0999 V2000 -0.5909 -0.6086 0.0018 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.2459 0.8185 -0.0936 C 0 0 0 0 0 0 0 0 0 0 0 0 0.8271 -0.1760 0.1017 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.1425 -0.9648 0.9113 H 0 0 0 0 0 0 0 0 0 0 0 0 -0.8767 -1.2011 -0.8967 H 0 0 0 0 0 0 0 0 0 0 0 0 -0.5849 1.4596 0.7584 H 0 0 0 0 0 0 0 0 0 0 0 0 -0.2393 1.3618 -1.0674 H 0 0 0 0 0 0 0 0 0 0 0 0 1.4853 -0.4161 -0.7761 H 0 0 0 0 0 0 0 0 0 0 0 0 1.3678 -0.2732 1.0608 H 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 0 2 3 1 0 3 1 1 0 1 4 1 0 1 5 1 0 2 6 1 0 2 7 1 0 3 8 1 0 3 9 1 0 M END `); assert.equal(mol3.has_coords(), 3); } function test_kekulize() { const badAromaticSmiles = 'c1cccc1'; var mol = null; try { mol = RDKitModule.get_mol(badAromaticSmiles); assert(mol === null); } catch { assert(mol === null); } mol = RDKitModule.get_mol(badAromaticSmiles, JSON.stringify({ kekulize: false })); assert(mol !== null); } function test_sanitize() { const badValenceSmiles = 'N(C)(C)(C)C'; var mol = null; try { mol = RDKitModule.get_mol(badValenceSmiles); assert(mol === null); } catch { assert(mol === null); } try { mol = RDKitModule.get_mol(badValenceSmiles, JSON.stringify({ kekulize: false })); assert(mol === null); } catch { assert(mol === null); } mol = RDKitModule.get_mol(badValenceSmiles, JSON.stringify({ sanitize: false })); assert(mol !== null); } function test_removehs() { const badValenceSmiles = 'N1C=CC(=O)c2ccc(N(C)(C)(C)(C)C)cc12'; mol = RDKitModule.get_mol(badValenceSmiles, JSON.stringify({ sanitize: false, removeHs: false })); assert(mol !== null); } function test_flexicanvas() { var mol = RDKitModule.get_mol("CCCC"); assert(mol !== null); var svg = mol.get_svg(-1,-1); assert(svg.search("svg")>0); assert(svg.search("width='87px'")>0); assert(svg.search("height='19px'")>0); } function test_run_reaction() { let rxn1; let molList; try { rxn1 = RDKitModule.get_rxn('[#6:1][O:2]>>[#6:1]=[O:2]'); molList = molListFromSmiArray(['CC(C)O',]); let products; try { products = rxn1.run_reactants(molList, 10000); for (let i = 0; i < products.size(); i++) { let element; try { element = products.get(i); let mol; try { mol = element.next(); assert(mol && mol.get_smiles() === "CC(C)=O"); } finally { if (mol) { mol.delete(); } } } finally { if (element) { element.delete(); } } } } finally { if (products) { products.delete(); } } } finally { if (rxn1) { rxn1.delete(); } if (molList) { molList.delete(); } } } function test_rxn_drawing() { { var rxn = RDKitModule.get_rxn("[CH3:1][OH:2]>>[CH2:1]=[OH0:2]"); var svg = rxn.get_svg(); assert(svg.search("svg") > 0); var rxn_from_block = RDKitModule.get_rxn(`$RXN RDKit 1 1 $MOL RDKit 2D 2 1 0 0 0 0 0 0 0 0999 V2000 0.0000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 1 0 0 1.2990 0.7500 0.0000 O 0 0 0 0 0 0 0 0 0 2 0 0 1 2 6 0 V 1 [C&H3:1] V 2 [O&H1:2] M END $MOL RDKit 2D 2 1 0 0 0 0 0 0 0 0999 V2000 0.0000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 1 0 0 1.2990 0.7500 0.0000 O 0 0 0 0 0 0 0 0 0 2 0 0 1 2 2 0 V 1 [C&H2:1] V 2 [O&H0:2] M END`); var svg_from_block = rxn_from_block.get_svg(); assert(svg_from_block.search("svg") > 0); assert(svg.match(/ 0); assert(svg.match(/C(Cl)Cl.C(=O)(C(=O)Cl)Cl>[cH:5]1[cH:6][c:7]2[cH:8][n:9][cH:10][cH:11][c:12]2[c:3]([cH:4]1)[C:2](=[O:1])[N:13]=[N+:14]=[N-:15]", JSON.stringify({ useSmiles: true })); { var svg = rxn.get_svg(); assert(svg.search("svg") > 0); assert(svg.search("stroke-dasharray" < 0)); assert(svg.search("ellipse") < 0); } { var svg = rxn.get_svg_with_highlights(JSON.stringify({ kekulize: false })); assert(svg.search("svg") > 0); assert(svg.search("stroke-dasharray" > 0)); assert(svg.search("ellipse") < 0); } { var svg = rxn.get_svg_with_highlights(JSON.stringify({ highlightByReactant: true })); assert(svg.search("svg") > 0); assert(svg.search("stroke-dasharray" < 0)); assert(svg.search("ellipse") > 0); assert(svg.search("#BCD6ED") < 0); assert(svg.search("#A8D08D") < 0); } { var svg = rxn.get_svg_with_highlights(JSON.stringify({ highlightColorsReactants: [[.741, .843, .933], [.659, .816, .553]] })); assert(svg.search("svg") > 0); assert(svg.search("stroke-dasharray" < 0)); assert(svg.search("ellipse") < 0); } { var svg = rxn.get_svg_with_highlights(JSON.stringify({ highlightByReactant: true, highlightColorsReactants: [[.741, .843, .933], [.659, .816, .553]] })); assert(svg.search("svg") > 0); assert(svg.search("stroke-dasharray" < 0)); assert(svg.search("ellipse") > 0); assert(svg.search("#BCD6ED") > 0); assert(svg.search("#A8D08D") > 0); } rxn.delete(); } { var rxn = RDKitModule.get_rxn("[cH:5]1[cH:6][c:7]2[cH:8][n:9][cH:10][cH:11][c:12]2[c:3]([cH:4]1)[C:2](=[O:1])O.[N-:13]=[N+:14]=[N-:15]>C(Cl)Cl.C(=O)(C(=O)Cl)Cl>[cH:5]1[cH:6][c:7]2[cH:8][n:9][cH:10][cH:11][c:12]2[c:3]([cH:4]1)[C:2](=[O:1])[N:13]=[N+:14]=[N-:15]"); var hasThrown = false; var isAromatic = false; // if the code is built with exception support it will not throw // but rather display molecules in their aromatic form rather // than kekulized try { var svg = rxn.get_svg(); isAromatic = svg.search("stroke-dasharray" > 0); } catch { hasThrown = true; } assert(isAromatic || hasThrown); } } function test_legacy_stereochem() { var origSetting; try { origSetting = RDKitModule.use_legacy_stereo_perception(true); var mol = RDKitModule.get_mol("O[C@@]1(C)C/C(/C1)=C(/C)\\CC"); assert(mol !== null); assert.equal(mol.get_smiles(),"CCC(C)=C1CC(C)(O)C1"); RDKitModule.use_legacy_stereo_perception(false); mol = RDKitModule.get_mol("O[C@@]1(C)C/C(/C1)=C(/C)\\CC"); assert(mol !== null); assert.equal(mol.get_smiles(),"CC/C(C)=C1\\C[C@](C)(O)C1"); } finally { RDKitModule.use_legacy_stereo_perception(origSetting); } } function test_allow_non_tetrahedral_chirality() { var ctab = ` Mrv2108 09132105183D 5 4 0 0 0 0 999 V2000 -1.2500 1.4518 0.0000 Pt 0 0 0 0 0 0 0 0 0 0 0 0 -1.2500 2.2768 0.0000 F 0 0 0 0 0 0 0 0 0 0 0 0 -0.4250 1.4518 0.0000 Cl 0 0 0 0 0 0 0 0 0 0 0 0 -2.0750 1.4518 0.0000 F 0 0 0 0 0 0 0 0 0 0 0 0 -1.2500 0.6268 0.0000 Cl 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 0 0 0 0 1 3 1 0 0 0 0 1 4 1 0 0 0 0 1 5 1 0 0 0 0 M END `; var origSetting; try { origSetting = RDKitModule.allow_non_tetrahedral_chirality(true); var mol = RDKitModule.get_mol(ctab); assert(mol !== null); assert.equal(mol.get_smiles(), "[F][Pt@SP3]([F])([Cl])[Cl]"); RDKitModule.allow_non_tetrahedral_chirality(false); var mol = RDKitModule.get_mol(ctab); assert(mol !== null); assert.equal(mol.get_smiles(), "[F][Pt]([F])([Cl])[Cl]"); } finally { RDKitModule.allow_non_tetrahedral_chirality(origSetting); } } function test_prop() { var mol = RDKitModule.get_mol(` MJ201900 2 1 0 0 0 0 0 0 0 0999 V2000 0.1899 1.9526 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.5245 1.5401 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2 1 1 0 0 0 0 M END `); assert.equal(mol.has_prop("test1"), false); assert.equal(mol.set_prop("test1","val"), true); assert.equal(mol.has_prop("test1"), true); assert.equal(mol.get_prop("test1"),"val"); assert.equal(mol.set_prop("test2","val"), true); props = mol.get_prop_list(false, false); assert.equal(props.get(0), "test1"); assert.equal(props.get(1), "test2"); assert.equal(mol.clear_prop("test3"), false); assert.equal(mol.has_prop("test2"), true); assert.equal(mol.clear_prop("test2"), true); assert.equal(mol.has_prop("test2"), false); } function test_highlights() { var mol = RDKitModule.get_mol('c1cc(O)ccc1'); var svg = mol.get_svg_with_highlights(JSON.stringify({ highlightAtomColors: { 0: [1.0, 0.0, 0.0], 1: [1.0, 0.0, 0.0], 2: [1.0, 0.0, 0.0], 3: [0.0, 1.0, 0.0], 4: [1.0, 0.0, 0.0], 5: [1.0, 0.0, 0.0], 6: [1.0, 0.0, 0.0], }, highlightBondColors: { 2: [0.0, 0.7, 0.9], }, highlightAtomRadii: { 0: 0.1, 1: 0.1, 2: 0.1, 3: 0.8, 4: 0.1, 5: 0.1, 6: 0.1, }, atoms: [0, 1, 2, 3, 4, 5, 6], bonds: [2], width: 127 })); assert(!svg.includes('fill:#FF7F7F')); assert(svg.includes('fill:#FF0000')); assert(svg.includes('fill:#00FF00')); assert(svg.includes('fill:#00B2E5')); assert(svg.includes("width='127px'")); assert(svg.includes('')); } function test_add_chiral_hs() { var mol = RDKitModule.get_mol(` MJ201100 18 21 0 0 1 0 0 0 0 0999 V2000 -0.8540 -1.4441 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.3019 -0.8310 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.5185 -0.9172 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.8540 -0.1635 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.6825 0.6434 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.1379 0.7296 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.5504 1.4441 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 -0.4734 -0.0239 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.2409 0.3885 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.6609 -1.2726 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.2130 -1.8857 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.9580 -2.6703 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.1511 -2.8419 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.5990 -2.2287 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -3.0201 -1.7143 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -3.5720 -2.3275 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -3.3171 -3.1121 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.5100 -3.2835 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 2 3 1 0 0 0 0 4 3 1 0 0 0 0 4 5 1 0 0 0 0 6 5 1 0 0 0 0 6 7 1 1 0 0 0 6 8 1 0 0 0 0 8 9 1 1 0 0 0 8 2 1 0 0 0 0 4 9 1 1 0 0 0 2 1 1 1 0 0 0 10 11 1 0 0 0 0 11 12 2 0 0 0 0 12 13 1 0 0 0 0 13 14 2 0 0 0 0 1 10 2 0 0 0 0 1 14 1 0 0 0 0 15 16 2 0 0 0 0 16 17 1 0 0 0 0 11 15 1 0 0 0 0 17 18 2 0 0 0 0 12 18 1 0 0 0 0 M END `); var quinoline_scaffold = RDKitModule.get_mol(` MJ201100 10 11 0 0 1 0 0 0 0 0999 V2000 -8.1001 2.8219 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 -8.8145 2.4094 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -8.8145 1.5843 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -8.1001 1.1718 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -7.3856 1.5843 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -7.3856 2.4094 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -6.6711 1.1718 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -5.9566 1.5842 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -5.9566 2.4092 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -6.6711 2.8218 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2 3 1 0 0 0 0 3 4 2 0 0 0 0 4 5 1 0 0 0 0 5 6 2 0 0 0 0 7 8 2 0 0 0 0 8 9 1 0 0 0 0 9 10 2 0 0 0 0 5 7 1 0 0 0 0 10 6 1 0 0 0 0 1 2 2 0 0 0 0 6 1 1 0 0 0 0 M END `); var svg1 = mol.get_svg_with_highlights(JSON.stringify({width: 350, height: 300})); assert(svg1.includes("width='350px'")); assert(svg1.includes("height='300px'")); assert(svg1.includes("")); assert(svg1.includes("atom-17")); assert(svg1.includes("atom-18")); assert(svg1.includes("atom-19")); var svg2 = mol.get_svg_with_highlights(JSON.stringify({ width: 350, height: 300, useMolBlockWedging: true, wedgeBonds: false, addChiralHs: false })); assert(svg2.includes("width='350px'")); assert(svg2.includes("height='300px'")); assert(svg2.includes("")); assert(svg2.includes("atom-17")); assert(!svg2.includes("atom-18")); assert(!svg2.includes("atom-19")); assert(mol.get_molblock().includes("4 3 1 6")); var molblock = mol.get_molblock(JSON.stringify({ useMolBlockWedging: true })); assert(!molblock.includes("4 3 1 6")); assert(molblock.includes("6 7 1 1")); // Here we want to test that the original molblock wedging is preserved and inverted // as the coordinates are rigid-body rotated var molCopy; molCopy = RDKitModule.get_mol_copy(mol); assert(JSON.parse(molCopy.generate_aligned_coords(quinoline_scaffold, JSON.stringify({ acceptFailure: false, alignOnly: true })))); molblock = molCopy.get_molblock(JSON.stringify({ useMolBlockWedging: true })); assert(molblock.split('\n').some(line => line.match(/^ [1 ]\d [1 ]\d [12] 6 *$/))); assert(!molblock.split('\n').some(line => line.match(/^ [1 ]\d [1 ]\d [12] 1 *$/))); assert(!molblock.includes("4 3 1 6")); assert(molblock.includes("6 7 1 6")); molCopy.delete(); // Here we want to test that the original molblock wedging gets cleared // and hence wedging is recomputed as the coordinates are re-generated molCopy = RDKitModule.get_mol_copy(mol); assert(JSON.parse(molCopy.generate_aligned_coords(quinoline_scaffold, JSON.stringify({ acceptFailure: false })))); molblock = molCopy.get_molblock(JSON.stringify({ useMolBlockWedging: true })); assert(molblock.split('\n').some(line => line.match(/^ [1 ]\d [1 ]\d [12] 6 *$/))); assert(molblock.split('\n').some(line => line.match(/^ [1 ]\d [1 ]\d [12] 1 *$/))); molCopy.delete(); mol.delete(); quinoline_scaffold.delete(); } function getWedgedMolAndInvertedWedges() { const wedgedMol = RDKitModule.get_mol(` RDKit 2D 29 34 0 0 1 0 0 0 0 0999 V2000 1.3719 5.1304 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 0.5985 3.7907 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.9482 3.7907 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.7216 5.1304 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -3.2685 5.1304 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -3.8994 3.5835 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.5597 4.3569 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.5597 5.9038 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -3.8994 6.6771 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -5.2389 5.9038 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -6.5784 6.6771 0.0000 F 0 0 0 0 0 0 0 0 0 0 0 0 -5.2389 4.3569 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1.3719 2.4510 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.5985 1.1115 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1.3719 -0.2276 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.9188 -0.2276 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 3.6921 1.1115 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.9188 2.4510 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 5.2389 1.1115 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 6.0124 -0.2276 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 5.2389 -1.5673 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 3.6921 -1.5673 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 3.8996 -5.0201 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 5.2391 -4.2467 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 3.5777 -6.5331 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 4.9909 -5.9040 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 6.0124 -2.9070 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 6.3306 -6.6772 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 6.5784 -5.0201 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2 1 1 1 2 3 1 0 3 4 1 0 5 4 1 6 5 6 1 0 6 7 1 0 7 8 1 0 9 8 1 1 5 9 1 0 9 10 1 0 10 11 1 1 10 12 1 0 6 12 1 1 2 13 1 0 13 14 2 0 14 15 1 0 15 16 2 0 16 17 1 0 17 18 2 0 13 18 1 0 17 19 1 0 19 20 1 0 20 21 1 0 21 22 1 0 16 22 1 0 23 24 1 0 23 25 1 0 25 26 1 0 24 27 1 0 27 26 1 0 26 28 1 0 24 29 1 0 28 29 1 0 21 27 1 0 M END `); const invertedWedges = ` 2 1 1 6 2 3 1 0 3 4 1 0 5 4 1 1 5 6 1 0 6 7 1 0 7 8 1 0 9 8 1 6 5 9 1 0 9 10 1 0 10 11 1 6 10 12 1 0 6 12 1 6 2 13 1 0 13 14 1 0 14 15 2 0 15 16 1 0 16 17 2 0 17 18 1 0 13 18 2 0 17 19 1 0 19 20 1 0 20 21 1 0 21 22 1 0 16 22 1 0 23 24 1 0 23 25 1 0 25 26 1 0 24 27 1 0 27 26 1 0 26 28 1 0 24 29 1 0 28 29 1 0 21 27 1 0 `; return { wedgedMol, invertedWedges }; } function test_wedging_all_within_scaffold() { const { wedgedMol, invertedWedges } = getWedgedMolAndInvertedWedges(); const scaffold = RDKitModule.get_mol(` RDKit 2D 13 14 0 0 1 0 0 0 0 0999 V2000 -1.6549 2.5755 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 -0.8814 1.2358 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.6653 1.2358 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1.4385 2.5755 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.9854 2.5755 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 3.6161 1.0286 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.2766 1.8019 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.2766 3.3487 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 3.6161 4.1222 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 4.9558 3.3487 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 6.2953 4.1222 0.0000 F 0 0 0 0 0 0 0 0 0 0 0 0 4.9558 1.8019 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.6549 -0.1037 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2 1 1 0 2 3 1 0 3 4 1 0 5 4 1 1 5 6 1 0 6 7 1 6 7 8 1 0 9 8 1 6 5 9 1 0 9 10 1 0 10 11 1 6 10 12 1 0 6 12 1 0 2 13 1 6 M END `); // the "alignOnly" alignment should succeed and preserve molblock wedging // (inverted with respect to the original molecule) // it should feature a narrow angle between the bridge bonds // as the original geometry of the bridge is preserved let wedgedMolCopy; wedgedMolCopy = RDKitModule.get_mol_copy(wedgedMol); assert(JSON.parse(wedgedMolCopy.generate_aligned_coords(scaffold, JSON.stringify({ acceptFailure: false, alignOnly: true })))); const mbAlignOnly = wedgedMolCopy.get_molblock(JSON.stringify({ useMolBlockWedging: true })); const svgAlignOnly = wedgedMolCopy.get_svg_with_highlights(JSON.stringify({ width: 350, height: 300, useMolBlockWedging: true, wedgeBonds: false, addChiralHs: false })); { const [xy23, xy26] = extractBondCoords(svgAlignOnly, 'atom-23 atom-26'); const [_, xy25] = extractBondCoords(svgAlignOnly, 'atom-26 atom-25'); const v1 = [xy23[0] - xy26[0], xy23[1] - xy26[1]]; const v2 = [xy25[0] - xy26[0], xy25[1] - xy26[1]]; const v1v2Theta = angleDegBetweenVectors(v1, v2); assert(v1v2Theta > 10 && v1v2Theta < 15); } assert(mbAlignOnly.includes(invertedWedges)); // the "rebuild" alignment should succeed and preserve molblock wedging // (inverted with respect to the original molecule) // it should feature a much wider angle between the bridge bonds as the // bridged system is entirely rebuilt since it is not part of the scaffold wedgedMolCopy.delete(); wedgedMolCopy = RDKitModule.get_mol_copy(wedgedMol); assert(JSON.parse(wedgedMolCopy.generate_aligned_coords(scaffold, JSON.stringify({ acceptFailure: false })))); const mbRebuild = wedgedMolCopy.get_molblock(JSON.stringify({ useMolBlockWedging: true })); const svgRebuild = wedgedMolCopy.get_svg_with_highlights(JSON.stringify({ width: 350, height: 300, useMolBlockWedging: true, wedgeBonds: false, addChiralHs: false })); { const [xy23, xy26] = extractBondCoords(svgRebuild, 'atom-23 atom-26'); const [_, xy25] = extractBondCoords(svgRebuild, 'atom-26 atom-25'); const v1 = [xy23[0] - xy26[0], xy23[1] - xy26[1]]; const v2 = [xy25[0] - xy26[0], xy25[1] - xy26[1]]; const v1v2Theta = angleDegBetweenVectors(v1, v2); assert(v1v2Theta > 105 && v1v2Theta < 110); } assert(mbRebuild.includes(invertedWedges)); // the "rebuildCoordGen" alignment should succeed and clear original wedging // it should feature an even wider angle between the bridge bonds as CoordGen // has a template for the bridged system. // Additionally, CoordGen also rebuilds the scaffold, therefore original wedging // should be cleared wedgedMolCopy.delete(); wedgedMolCopy = RDKitModule.get_mol_copy(wedgedMol); assert(JSON.parse(wedgedMolCopy.generate_aligned_coords(scaffold, JSON.stringify({ acceptFailure: false, useCoordGen: true })))); const mbRebuildCoordGen = wedgedMolCopy.get_molblock(JSON.stringify({ useMolBlockWedging: true })); const svgRebuildCoordGen = wedgedMolCopy.get_svg_with_highlights(JSON.stringify({ width: 350, height: 300, useMolBlockWedging: true, wedgeBonds: false, addChiralHs: false })); { const [xy23, xy26] = extractBondCoords(svgRebuildCoordGen, 'atom-23 atom-26'); const [_, xy25] = extractBondCoords(svgRebuildCoordGen, 'atom-26 atom-25'); const v1 = [xy23[0] - xy26[0], xy23[1] - xy26[1]]; const v2 = [xy25[0] - xy26[0], xy25[1] - xy26[1]]; const v1v2Theta = angleDegBetweenVectors(v1, v2); assert(v1v2Theta > 145 && v1v2Theta < 150); } assert(!mbRebuildCoordGen.includes(invertedWedges)); wedgedMolCopy.delete(); } function test_wedging_outside_scaffold() { const { wedgedMol, invertedWedges } = getWedgedMolAndInvertedWedges(); const scaffold = RDKitModule.get_mol(` RDKit 2D 9 10 0 0 1 0 0 0 0 0999 V2000 -0.8816 0.5663 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.6651 0.5663 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1.2958 -0.9804 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.0435 -0.2072 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.0435 1.3395 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1.2958 2.1129 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.6355 1.3395 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 3.9750 2.1129 0.0000 F 0 0 0 0 0 0 0 0 0 0 0 0 2.6355 -0.2072 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2 1 1 1 2 3 1 0 3 4 1 6 4 5 1 0 6 5 1 6 2 6 1 0 6 7 1 0 7 8 1 6 7 9 1 0 3 9 1 0 M END `); let wedgedMolCopy; wedgedMolCopy = RDKitModule.get_mol_copy(wedgedMol); // the "alignOnly" alignment should succeed and preserve molblock wedging // (inverted with respect to the original molecule) // it should feature a narrow angle between the bridge bonds // as the original geometry of the bridge is preserved assert(JSON.parse(wedgedMolCopy.generate_aligned_coords(scaffold, JSON.stringify({ acceptFailure: false, alignOnly: true })))); const mbAlignOnly = wedgedMolCopy.get_molblock(JSON.stringify({ useMolBlockWedging: true })); const svgAlignOnly = wedgedMolCopy.get_svg_with_highlights(JSON.stringify({ width: 350, height: 300, useMolBlockWedging: true, wedgeBonds: false, addChiralHs: false })); { const [xy23, xy26] = extractBondCoords(svgAlignOnly, 'atom-23 atom-26'); const [_, xy25] = extractBondCoords(svgAlignOnly, 'atom-26 atom-25'); const v1 = [xy23[0] - xy26[0], xy23[1] - xy26[1]]; const v2 = [xy25[0] - xy26[0], xy25[1] - xy26[1]]; const v1v2Theta = angleDegBetweenVectors(v1, v2); assert(v1v2Theta > 10 && v1v2Theta < 15); } assert(mbAlignOnly.includes(invertedWedges)); // the "rebuild" alignment should succeed and clear original wedging // it should feature a much wider angle between the bridge bonds as the // bridged system is entirely rebuilt since it is not part of the scaffold wedgedMolCopy.delete(); wedgedMolCopy = RDKitModule.get_mol_copy(wedgedMol); assert(JSON.parse(wedgedMolCopy.generate_aligned_coords(scaffold, JSON.stringify({ acceptFailure: false })))); const mbRebuild = wedgedMolCopy.get_molblock(JSON.stringify({ useMolBlockWedging: true })); const svgRebuild = wedgedMolCopy.get_svg_with_highlights(JSON.stringify({ width: 350, height: 300, useMolBlockWedging: true, wedgeBonds: false, addChiralHs: false })); { const [xy23, xy26] = extractBondCoords(svgRebuild, 'atom-23 atom-26'); const [_, xy25] = extractBondCoords(svgRebuild, 'atom-26 atom-25'); const v1 = [xy23[0] - xy26[0], xy23[1] - xy26[1]]; const v2 = [xy25[0] - xy26[0], xy25[1] - xy26[1]]; const v1v2Theta = angleDegBetweenVectors(v1, v2); assert(v1v2Theta > 105 && v1v2Theta < 110); } assert(!mbRebuild.includes(invertedWedges)); // the "rebuildCoordGen" alignment should succeed and clear original wedging // it should feature an even wider angle between the bridge bonds as CoordGen // has a template for the bridged system. // Additionally, CoordGen also rebuilds the scaffold, therefore original wedging // should be cleared wedgedMolCopy.delete(); wedgedMolCopy = RDKitModule.get_mol_copy(wedgedMol); assert(JSON.parse(wedgedMolCopy.generate_aligned_coords(scaffold, JSON.stringify({ acceptFailure: false, useCoordGen: true })))); const mbRebuildCoordGen = wedgedMolCopy.get_molblock(JSON.stringify({ useMolBlockWedging: true })); const svgRebuildCoordGen = wedgedMolCopy.get_svg_with_highlights(JSON.stringify({ width: 350, height: 300, useMolBlockWedging: true, wedgeBonds: false, addChiralHs: false })); { const [xy23, xy26] = extractBondCoords(svgRebuildCoordGen, 'atom-23 atom-26'); const [_, xy25] = extractBondCoords(svgRebuildCoordGen, 'atom-26 atom-25'); const v1 = [xy23[0] - xy26[0], xy23[1] - xy26[1]]; const v2 = [xy25[0] - xy26[0], xy25[1] - xy26[1]]; const v1v2Theta = angleDegBetweenVectors(v1, v2); assert(v1v2Theta > 145 && v1v2Theta < 150); } assert(!mbRebuildCoordGen.includes(invertedWedges)); wedgedMolCopy.delete(); } function test_wedging_if_no_match() { const { wedgedMol, invertedWedges } = getWedgedMolAndInvertedWedges(); const scaffoldNoMatch = RDKitModule.get_mol(` RDKit 2D 13 14 0 0 1 0 0 0 0 0999 V2000 -1.6549 2.5755 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 -0.8814 1.2358 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.6653 1.2358 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1.4385 2.5755 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.9854 2.5755 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 3.6161 1.0286 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.2766 1.8019 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.2766 3.3487 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 3.6161 4.1222 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 4.9558 3.3487 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 6.2953 4.1222 0.0000 Cl 0 0 0 0 0 0 0 0 0 0 0 0 4.9558 1.8019 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.6549 -0.1037 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2 1 1 0 2 3 1 0 3 4 1 0 5 4 1 1 5 6 1 0 6 7 1 6 7 8 1 0 9 8 1 6 5 9 1 0 9 10 1 0 10 11 1 6 10 12 1 0 6 12 1 0 2 13 1 6 M END `); let wedgedMolCopy; let mb; const origMolBlock = wedgedMol.get_molblock(JSON.stringify({ useMolBlockWedging: true })); // the "alignOnly" alignment should return "" if acceptFailure is false // and preserve the original coordinates wedgedMolCopy = RDKitModule.get_mol_copy(wedgedMol); assert(wedgedMolCopy.generate_aligned_coords(scaffoldNoMatch, JSON.stringify({ acceptFailure: false, alignOnly: true })) === ""); mb = wedgedMolCopy.get_molblock(JSON.stringify({ useMolBlockWedging: true })); assert(mb === origMolBlock); assert(!mb.includes(invertedWedges)); wedgedMolCopy.delete(); // the "alignOnly" alignment should return "{}" if acceptFailure is true // and generate new coordinates, hence wedging should be cleared wedgedMolCopy = RDKitModule.get_mol_copy(wedgedMol); assert(wedgedMolCopy.generate_aligned_coords(scaffoldNoMatch, JSON.stringify({ acceptFailure: true, alignOnly: true })) === "{}"); mb = wedgedMolCopy.get_molblock(JSON.stringify({ useMolBlockWedging: true })); assert(mb !== origMolBlock); assert(!mb.includes(invertedWedges)); wedgedMolCopy.delete(); // the "rebuild" alignment should return "" if acceptFailure is false // and preserve the original coordinates wedgedMolCopy = RDKitModule.get_mol_copy(wedgedMol); assert(wedgedMolCopy.generate_aligned_coords(scaffoldNoMatch, JSON.stringify({ acceptFailure: false })) === ""); mb = wedgedMolCopy.get_molblock(JSON.stringify({ useMolBlockWedging: true })); assert(mb === origMolBlock); assert(!mb.includes(invertedWedges)); wedgedMolCopy.delete(); // the "rebuild" alignment should return "{}" if acceptFailure is true // and generate new coordinates, hence wedging should be cleared wedgedMolCopy = RDKitModule.get_mol_copy(wedgedMol); assert(wedgedMolCopy.generate_aligned_coords(scaffoldNoMatch, JSON.stringify({ acceptFailure: true })) === "{}"); mb = wedgedMolCopy.get_molblock(JSON.stringify({ useMolBlockWedging: true })); assert(mb !== origMolBlock); assert(!mb.includes(invertedWedges)); wedgedMolCopy.delete(); // the "rebuildCoordGen" alignment should return "" if acceptFailure is false // and preserve the original coordinates wedgedMolCopy = RDKitModule.get_mol_copy(wedgedMol); assert(wedgedMolCopy.generate_aligned_coords(scaffoldNoMatch, JSON.stringify({ acceptFailure: false, useCoordGen: true })) === ""); mb = wedgedMolCopy.get_molblock(JSON.stringify({ useMolBlockWedging: true })); assert(mb === origMolBlock); assert(!mb.includes(invertedWedges)); wedgedMolCopy.delete(); // the "rebuildCoordGen" alignment should return "{}" if acceptFailure is true // and generate new coordinates, hence wedging should be cleared wedgedMolCopy = RDKitModule.get_mol_copy(wedgedMol); assert(wedgedMolCopy.generate_aligned_coords(scaffoldNoMatch, JSON.stringify({ acceptFailure: true, useCoordGen: true })) === "{}"); mb = wedgedMolCopy.get_molblock(JSON.stringify({ useMolBlockWedging: true })); assert(mb !== origMolBlock); assert(!mb.includes(invertedWedges)); wedgedMolCopy.delete(); } function test_get_frags() { { var mol = RDKitModule.get_mol("n1ccccc1.CC(C)C.OCCCN"); var expectedFragSmiles = ["c1ccncc1", "CC(C)C", "NCCCO"]; var expectedFragSmilesNonSanitized = ["CN(C)(C)C", "c1ccc1"]; var expectedMappings = { frags: [0,0,0,0,0,0,1,1,1,1,2,2,2,2,2], fragsMolAtomMapping: [[0,1,2,3,4,5],[6,7,8,9],[10,11,12,13,14]], }; var { molList, mappings } = mol.get_frags(); assert.equal(molList.size(), 3); assert(JSON.stringify(JSON.parse(mappings)) === JSON.stringify(expectedMappings)); var i = 0; while (!molList.at_end()) { var mol = molList.next(); assert(mol.get_smiles() === expectedFragSmiles[i++]); mol.delete(); } assert(!molList.next()); molList.delete(); } { var mol = RDKitModule.get_mol("N(C)(C)(C)C.c1ccc1", JSON.stringify({sanitize: false})); var exceptionThrown = false; try { mol.get_frags(); } catch (e) { exceptionThrown = true; } assert(exceptionThrown); var { molList, mappings } = mol.get_frags(JSON.stringify({sanitizeFrags: false})); assert.equal(molList.size(), 2); var i = 0; while (!molList.at_end()) { var mol = molList.next(); assert(mol.get_smiles() === expectedFragSmilesNonSanitized[i++]); mol.delete(); } assert(!molList.next()); molList.delete(); } } function test_get_mmpa_frags() { { var mol = RDKitModule.get_mol("CC(C)CCN1C(=O)CN=C(c2ccccc12)C3CCCCC3"); var expectedCores = ["O=C1CN=C(C2CCCCC2)c2ccccc2N1CCC([*:1])[*:2]", "CC([*:1])[*:2]", "CC(C[*:2])[*:1]", "CC(CC[*:2])[*:1]", "CC(CCN1C(=O)CN=C([*:2])c2ccccc21)[*:1]", "C([*:1])[*:2]", "C(C[*:2])[*:1]", "O=C1CN=C([*:2])c2ccccc2N1CC[*:1]", "C([*:1])[*:2]", "O=C1CN=C([*:1])c2ccccc2N1C[*:2]", "O=C1CN=C([*:1])c2ccccc2N1[*:2]"]; var expectedSidechains = ["C[*:1].C[*:2]", "C[*:1].O=C1CN=C(C2CCCCC2)c2ccccc2N1CC[*:2]", "C[*:1].O=C1CN=C(C2CCCCC2)c2ccccc2N1C[*:2]", "C[*:1].O=C1CN=C(C2CCCCC2)c2ccccc2N1[*:2]", "C1CCC([*:2])CC1.C[*:1]", "CC(C)[*:1].O=C1CN=C(C2CCCCC2)c2ccccc2N1C[*:2]", "CC(C)[*:1].O=C1CN=C(C2CCCCC2)c2ccccc2N1[*:2]", "C1CCC([*:2])CC1.CC(C)[*:1]", "CC(C)C[*:1].O=C1CN=C(C2CCCCC2)c2ccccc2N1[*:2]", "C1CCC([*:1])CC1.CC(C)C[*:2]", "C1CCC([*:1])CC1.CC(C)CC[*:2]"]; var pairs = mol.get_mmpa_frags(2, 2, 20); assert(pairs.cores); assert.equal(pairs.cores.size(), 11); assert(pairs.sidechains); assert.equal(pairs.sidechains.size(), 11); var i = 0; while (!pairs.cores.at_end()) { var m = pairs.cores.next(); assert(m.get_smiles() === expectedCores[i++]); m.delete(); } i = 0; while (!pairs.sidechains.at_end()) { var m = pairs.sidechains.next(); assert(m.get_smiles() === expectedSidechains[i++]); m.delete(); } assert(!pairs.cores.next()); assert(!pairs.sidechains.next()); pairs.cores.delete(); pairs.sidechains.delete(); mol.delete(); } { var mol = RDKitModule.get_mol("CC(C)CCN1C(=O)CN=C(c2ccccc12)C3CCCCC3"); var expectedSidechains = ["CC(CCN1C(=O)CN=C(C2CCCCC2)c2ccccc21)[*:1].C[*:1]", "CC(C)[*:1].O=C1CN=C(C2CCCCC2)c2ccccc2N1CC[*:1]", "CC(C)C[*:1].O=C1CN=C(C2CCCCC2)c2ccccc2N1C[*:1]", "CC(C)CC[*:1].O=C1CN=C(C2CCCCC2)c2ccccc2N1[*:1]", "C1CCC([*:1])CC1.CC(C)CCN1C(=O)CN=C([*:1])c2ccccc21"]; var pairs = mol.get_mmpa_frags(1, 1, 20); assert(pairs.cores); assert.equal(pairs.cores.size(), 5); assert(pairs.sidechains); assert.equal(pairs.sidechains.size(), 5); while (!pairs.cores.at_end()) { var m = pairs.cores.next(); assert(m === null); } var i = 0; while (!pairs.sidechains.at_end()) { var m = pairs.sidechains.next(); assert(m.get_smiles() === expectedSidechains[i++]); m.delete(); } assert(!pairs.cores.next()); assert(!pairs.sidechains.next()); var numCores = pairs.cores.size(); for (i = 0; i < numCores; ++i) { assert(pairs.cores.at(i) === null); } for (i = 0; i < numCores; ++i) { assert(pairs.cores.pop(0) === null); } assert.equal(pairs.cores.size(), 0); assert(pairs.cores.next() === null); pairs.cores.delete(); pairs.sidechains.delete(); mol.delete(); } } function test_molzip() { { var mol1 = RDKitModule.get_mol("F/C=C/[*:1]"); assert(mol1); var mol2 = RDKitModule.get_mol("[*:1]F"); assert(mol2); var expectedLinkage = "F/C=C/F"; var mol = RDKitModule.molzip(mol1, mol2); assert(mol); assert(mol.get_smiles() === expectedLinkage); mol1.delete(); mol2.delete(); mol.delete(); } { var mol1 = RDKitModule.get_mol("[C@H]([Xe])(F)([V])"); assert(mol1); var mol2 = RDKitModule.get_mol("[Xe]N.[V]I"); assert(mol2); var expectedLinkage = "N[C@@H](F)I"; var details = JSON.stringify({ Label: 'AtomType', AtomSymbols: ['Xe', 'V'] }); var mol = RDKitModule.molzip(mol1, mol2, details); assert(mol); assert(mol.get_smiles() === expectedLinkage); mol1.delete(); mol2.delete(); mol.delete(); } if (RDKitModule.RGroupDecomposition) { const smis = ['C1CN[C@H]1F', 'C1CN[C@]1(O)F', 'C1CN[C@@H]1F', 'C1CN[CH]1F']; const core = RDKitModule.get_qmol('C1CNC1[*:1]'); const params = { rgroupLabelling: 'Isotope', allowMultipleRGroupsOnUnlabelled: true, }; const rgd = RDKitModule.get_rgd(core, JSON.stringify(params)); const smisCanon = smis.map((smi, i) => { const mol = RDKitModule.get_mol(smi); assert(mol); try { const res = rgd.add(mol); assert(res === i); return mol.get_smiles(); } finally { mol.delete(); } }); rgd.process(); const rows = rgd.get_rgroups_as_rows(); const expectedRowMapping = [ { Core: '[1*][C@@]1([2*])CCN1', R1: '[1*]F', R2: '[2*][H]' }, { Core: '[1*][C@]1([2*])CCN1', R1: '[1*]F', R2: '[2*]O' }, { Core: '[1*][C@]1([2*])CCN1', R1: '[1*]F', R2: '[2*][H]' }, { Core: '[1*]C1([2*])CCN1', R1: '[1*]F', R2: '[2*][H]' }, ]; const details = JSON.stringify({ Label: 'Isotope' }); rows.forEach((row, i) => { const foundMapping = getFoundRgdRowAsMap(row, true); assert(Object.keys(foundMapping).length === Object.keys(expectedRowMapping[i]).length); Object.entries(foundMapping).forEach(([rlabel, smi]) => { assert(expectedRowMapping[i][rlabel] && expectedRowMapping[i][rlabel] === smi); }); let mol; try { mol = RDKitModule.molzip(row, details); assert(mol); mol.remove_hs_in_place(); assert(mol.get_smiles() === smisCanon[i]); } finally { if (mol) { mol.delete(); } Object.values(row).forEach((rgroup) => { if (rgroup) { rgroup.delete(); } }); } }); } } function test_hs_in_place() { { var mol = RDKitModule.get_mol("CC"); assert(!mol.has_coords()); var descNoH = JSON.parse(mol.get_descriptors()); assert(`${descNoH.chi0v}` === '2'); assert(`${descNoH.chi1v}` === '1'); mol.add_hs_in_place(); assert(!mol.has_coords()); assert(mol.get_smiles() === '[H]C([H])([H])C([H])([H])[H]'); var descH = JSON.parse(mol.get_descriptors()); assert(`${descH.chi0v}` === '1'); assert(`${descH.chi1v}` === '0.25'); mol.delete(); } { var mol = RDKitModule.get_mol("C([H])([H])([H])C([H])([H])[H]", JSON.stringify({ removeHs: false })); assert(mol.get_smiles() === '[H]C([H])([H])C([H])([H])[H]'); assert(!mol.has_coords()); var descH = JSON.parse(mol.get_descriptors()); assert(`${descH.chi0v}` === '1'); assert(`${descH.chi1v}` === '0.25'); // '' will use removeAllHs, while '{}' will use removeHs with default parameters ['', '{}'].forEach((details) => { var molCopy = mol.copy(); molCopy.remove_hs_in_place(details); assert(!molCopy.has_coords()); assert(molCopy.get_smiles() === 'CC'); var descNoH = JSON.parse(molCopy.get_descriptors()); assert(`${descNoH.chi0v}` === '2'); assert(`${descNoH.chi1v}` === '1'); molCopy.delete(); }); mol.delete(); } { var mol = RDKitModule.get_mol(` MJ201100 2 1 0 0 0 0 0 0 0 0999 V2000 -13.9955 5.1116 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -13.2810 5.5241 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 0 0 0 0 M END `); assert(mol.has_coords()); assert(mol.get_molblock() === ` RDKit 2D 2 1 0 0 0 0 0 0 0 0999 V2000 -13.9955 5.1116 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -13.2810 5.5241 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 0 M END `); var descNoH = JSON.parse(mol.get_descriptors()); assert(`${descNoH.chi0v}` === '2'); assert(`${descNoH.chi1v}` === '1'); mol.add_hs_in_place(); assert(mol.has_coords()); assert(mol.get_smiles() === '[H]C([H])([H])C([H])([H])[H]'); var descH = JSON.parse(mol.get_descriptors()); assert(`${descH.chi0v}` === '1'); assert(`${descH.chi1v}` === '0.25'); assert(mol.get_molblock().includes(` RDKit 2D 8 7 0 0 0 0 0 0 0 0999 V2000 -13.9955 5.1116 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -13.2810 5.5241 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 `)); assert(mol.get_molblock().includes(` 1 2 1 0 1 3 1 0 1 4 1 0 1 5 1 0 2 6 1 0 2 7 1 0 2 8 1 0 M END `)); mol.delete(); } { var mol = RDKitModule.get_mol(` MJ201100 8 7 0 0 0 0 0 0 0 0999 V2000 -13.9955 5.1116 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -13.2810 5.5241 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -14.4080 5.8260 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 -14.7100 4.6991 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 -13.5830 4.3971 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 -12.8685 4.8096 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 -12.5665 5.9366 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 -13.6935 6.2385 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 0 0 0 0 1 3 1 0 0 0 0 1 4 1 0 0 0 0 1 5 1 0 0 0 0 2 6 1 0 0 0 0 2 7 1 0 0 0 0 2 8 1 0 0 0 0 M END `, JSON.stringify({ removeHs: false })); assert(mol.has_coords()); assert(mol.get_molblock() === ` RDKit 2D 8 7 0 0 0 0 0 0 0 0999 V2000 -13.9955 5.1116 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -13.2810 5.5241 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -14.4080 5.8260 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 -14.7100 4.6991 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 -13.5830 4.3971 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 -12.8685 4.8096 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 -12.5665 5.9366 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 -13.6935 6.2385 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 0 1 3 1 0 1 4 1 0 1 5 1 0 2 6 1 0 2 7 1 0 2 8 1 0 M END `); var descH = JSON.parse(mol.get_descriptors()); assert(`${descH.chi0v}` === '1'); assert(`${descH.chi1v}` === '0.25'); mol.remove_hs_in_place(); assert(mol.has_coords()); assert(mol.get_smiles() === 'CC'); var descNoH = JSON.parse(mol.get_descriptors()); assert(`${descNoH.chi0v}` === '2'); assert(`${descNoH.chi1v}` === '1'); assert(mol.get_molblock() === ` RDKit 2D 2 1 0 0 0 0 0 0 0 0999 V2000 -13.9955 5.1116 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -13.2810 5.5241 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 0 M END `); mol.delete(); } } function test_query_colour() { var mol; try { mol = RDKitModule.get_qmol('c1ccc2nc([*:1])nc([*:2])c2c1'); var svg1 = mol.get_svg_with_highlights(JSON.stringify({width: 350, height: 300})); assert(svg1.includes("width='350px'")); assert(svg1.includes("height='300px'")); assert(svg1.includes("")); assert(svg1.includes("#7F7F7F")); var svg2 = mol.get_svg_with_highlights(JSON.stringify({width: 350, height: 300, queryColour: [0.0, 0.0, 0.0]})); assert(svg2.includes("width='350px'")); assert(svg2.includes("height='300px'")); assert(svg2.includes("")); assert(!svg2.includes("#7F7F7F")); } finally { if (mol) { mol.delete(); } } } function test_alignment_r_groups_aromatic_ring() { var mol; var scaffold; try { mol = RDKitModule.get_mol('c1ccc2nccnc2c1'); assert(mol !== null); scaffold = RDKitModule.get_mol(` MJ201100 8 8 0 0 0 0 0 0 0 0999 V2000 -1.0263 -0.3133 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0 -2.4553 0.5116 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0 -1.7408 -0.7258 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.7408 -1.5509 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.4553 -1.9633 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -3.1698 -1.5509 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -3.1698 -0.7258 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.4553 -0.3133 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 3 1 1 0 0 0 0 8 2 1 0 0 0 0 4 3 2 0 0 0 0 5 4 1 0 0 0 0 6 5 2 0 0 0 0 7 6 1 0 0 0 0 8 3 1 0 0 0 0 8 7 2 0 0 0 0 M RGP 2 1 2 2 1 M END`); assert(scaffold !== null); var res = mol.generate_aligned_coords(scaffold, JSON.stringify({useCoordGen: true, allowRGroups: true})); assert(res); assert.equal(JSON.parse(res).atoms.length, 8); assert.equal(JSON.parse(res).bonds.length, 8); } finally { if (mol) { mol.delete(); } } try { mol = RDKitModule.get_mol(` MJ201100 10 11 0 0 0 0 0 0 0 0999 V2000 3.6937 2.5671 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.8687 2.5671 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.4561 1.8526 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.8687 1.1382 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 3.6937 1.1381 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 4.1062 1.8526 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 4.9313 1.8527 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 5.3438 2.5671 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 4.9313 3.2816 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 4.1062 3.2816 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 5 6 1 0 0 0 0 4 5 2 0 0 0 0 3 4 1 0 0 0 0 2 3 2 0 0 0 0 1 6 2 0 0 0 0 1 2 1 0 0 0 0 8 9 1 0 0 0 0 9 10 2 0 0 0 0 10 1 1 0 0 0 0 7 8 2 0 0 0 0 6 7 1 0 0 0 0 M END`); var res = mol.generate_aligned_coords(scaffold, JSON.stringify({allowRGroups: true, alignOnly: true})); assert(res); assert.equal(JSON.parse(res).atoms.length, 8); assert.equal(JSON.parse(res).bonds.length, 8); } finally { if (mol) { mol.delete(); } if (scaffold) { scaffold.delete(); } } } function test_is_valid_deprecated() { var mol = RDKitModule.get_mol('C'); assert(mol !== null); assert(mol.is_valid()); var mol; try { mol = RDKitModule.get_mol('CN(C)(C)C'); } catch (e) { // in case MinimalLib was built without exception support mol = null; } assert(mol === null); if (RDKitModule.get_rxn) { var rxn; rxn = RDKitModule.get_rxn('C>>N'); assert(rxn !== null); try { rxn = RDKitModule.get_rxn('Z>>C'); } catch (e) { // in case MinimalLib was built without exception support rxn = null; } assert(rxn === null); } } function molListFromSmiArray(smiArray) { const molList = new RDKitModule.MolList(); assert(molList); smiArray.forEach((smiName) => { const [smi, name] = smiName.split(' '); let mol; try { mol = RDKitModule.get_mol(smi); assert(mol); molList.append(mol); } finally { if (mol) { mol.delete(); } } }); return molList; } function test_mol_list() { const smiArray = [ 'C1CC1', 'C1CCCC1' ]; let molList; let mol; try { molList = molListFromSmiArray(smiArray); assert(molList); assert.equal(molList.size(), 2); assert(!molList.at_end()); try { mol = molList.next(); assert(mol); } finally { if (mol) { mol.delete(); } } try { mol = molList.next(); assert(mol); } finally { if (mol) { mol.delete(); } } mol = molList.next(); assert(!mol); assert(molList.at_end()); try { mol = molList.at(0); assert.equal(mol.get_num_atoms(), 3); } finally { if (mol) { mol.delete(); } } try { mol = molList.at(1); assert.equal(mol.get_num_atoms(), 5); } finally { if (mol) { mol.delete(); } } assert(molList.at_end()); try { mol = RDKitModule.get_mol('C1CCC1'); assert(mol); molList.insert(1, mol); assert.equal(molList.size(), 3); assert(!molList.at_end()); } finally { if (mol) { mol.delete(); } } molList.reset(); assert(!molList.at_end()); try { mol = molList.at(1); assert.equal(mol.get_num_atoms(), 4); } finally { if (mol) { mol.delete(); } } try { mol = molList.pop(0); assert.equal(mol.get_num_atoms(), 3); } finally { if (mol) { mol.delete(); } } assert.equal(molList.size(), 2); // Modifications to molecules in the molList should persist // as the underlying C++ object is a shared_ptr [0, 1].forEach((loopIdx) => { let i = 0; molList.reset(); while (!molList.at_end()) { try { mol = molList.next(); assert(mol); if (loopIdx == 0) { assert(!mol.has_prop('molIdx')); mol.set_prop('molIdx', `${++i}`); } else { assert(mol.has_prop('molIdx')); i = parseInt(mol.get_prop('molIdx')); } } finally { if (mol) { mol.delete(); } } } assert.equal(i, 2); assert(molList.at_end()); }); try { mol = molList.pop(0); assert.equal(mol.get_num_atoms(), 4); } finally { if (mol) { mol.delete(); } } assert.equal(molList.size(), 1); assert(molList.at_end()); try { mol = molList.pop(0); assert.equal(mol.get_num_atoms(), 5); } finally { if (mol) { mol.delete(); } } assert.equal(molList.size(), 0); assert(molList.at_end()); assert(!molList.pop(0)); try { mol = RDKitModule.get_mol('C1CCCCC1'); assert(mol); molList.append(mol); assert.equal(molList.size(), 1); assert(!molList.at_end()); } finally { if (mol) { mol.delete(); } } assert(!molList.at(1)); try { mol = molList.at(0); assert(mol); assert(mol.get_num_atoms(), 6); } finally { if (mol) { mol.delete(); } } } finally { if (molList) { molList.delete(); } } } function test_mcs() { { const smiArray = [ "COc1cc2nc(-c3cc(NC(=O)CSc4ccc(Cl)cc4)ccc3)oc2cc1 CHEMBL1479679", "COc1cc2nc(-c3cc(NC(=O)CSc4ccc(Cl)cc4)c(C)cc3)oc2cc1 CHEMBL1333382", "Cc1cc2oc(-c3cc(NC(=O)CSc4ccc(Cl)cc4)ccc3)nc2cc1 CHEMBL1437584", "COc1c(NC(=O)CSc2ccc(Cl)cc2)cc(-c2nc3ccccc3o2)cc1 CHEMBL1601350", "Cc1cc2nc(-c3cccc(NC(=O)CSc4ccc(Cl)cc4)c3)oc2cc1C CHEMBL1398008", "Cc1cc2oc(-c3cc(NC(=O)CSc4ccc(Cl)cc4)c(C)cc3)nc2cc1 CHEMBL1612903", "COc1cc2nc(-c3cc(NC(=O)Cc4ccc(Cl)cc4)c(C)cc3)oc2cc1 CHEMBL1316483", "Cc1c(NC(=O)CSc2ccc(Cl)cc2)cccc1-c1nc2cc(Cl)ccc2o1 CHEMBL1568754", "COc1ccc2oc(-c3ccc(C)c(NC(=O)COc4cc(C)cc(C)c4)c3)nc2c1 CHEMBL1436972", "Cc1ccc(SCC(=O)Nc2cc(-c3nc4cc(C)ccc4o3)c(O)cc2)cc1 CHEMBL1611932", ]; let molList; let mcsSmarts; try { molList = molListFromSmiArray(smiArray); let mcsMol; try { mcsMol = RDKitModule.get_mcs_as_mol(molList); assert(mcsMol); assert.equal(mcsMol.get_smarts(), '[#6]1:[#6]:[#6]2:[#8]:[#6](:[#7]:[#6]:2:[#6]:[#6]:1)-[#6]1:[#6]:[#6](-[#7]-[#6](=[#8])-[#6]):[#6]:[#6]:[#6]:1'); mcsSmarts = RDKitModule.get_mcs_as_smarts(molList); } finally { if (mcsMol) { mcsMol.delete(); } } } finally { if (molList) { molList.delete(); } } assert(mcsSmarts); assert.equal(mcsSmarts, '[#6]1:[#6]:[#6]2:[#8]:[#6](:[#7]:[#6]:2:[#6]:[#6]:1)-[#6]1:[#6]:[#6](-[#7]-[#6](=[#8])-[#6]):[#6]:[#6]:[#6]:1'); } { const smiArray = ["C1CC1N2CC2", "C1CC1N"]; let molList; try { molList = molListFromSmiArray(smiArray); let mcsMol; try { mcsMol = RDKitModule.get_mcs_as_mol(molList); assert(mcsMol); assert.equal(mcsMol.get_num_atoms(), 4); assert.equal(mcsMol.get_num_bonds(), 4); } finally { if (mcsMol) { mcsMol.delete(); } } try { mcsMol = RDKitModule.get_mcs_as_mol(molList, JSON.stringify({ RingMatchesRingOnly: true })); assert(mcsMol); assert.equal(mcsMol.get_num_atoms(), 3); assert.equal(mcsMol.get_num_bonds(), 3); } finally { if (mcsMol) { mcsMol.delete(); } } } finally { if (molList) { molList.delete(); } } } { const smiArray = ["NC1CCCCC1", "Cc1ccccc1", "Cc1cnccc1", "CC1CCCCN1"]; let molList; const res = new Set(); try { molList = molListFromSmiArray(smiArray); ["Elements", "Any"].forEach((AtomCompare) => { ["Order", "OrderExact"].forEach((BondCompare) => { const details = { AtomCompare, BondCompare }; let mcsSmarts; mcsSmarts = RDKitModule.get_mcs_as_smarts(molList, JSON.stringify(details)); assert(mcsSmarts); res.add(mcsSmarts); }); }); } finally { if (molList) { molList.delete(); } } assert.equal(res.size, 4); } { const smiArray = [ "c1cccc(c12)ccc(c2)-c3n(CCC[NH3+])c(nn3)SCCc4c[nH]c(c45)cccc5", "c1cccc(c12)sc(c2)-c3n(CCCC[NH3+])c(nn3)SCCc4c[nH]c(c45)cccc5", ]; let molList; let mcs; try { molList = molListFromSmiArray(smiArray); mcs = RDKitModule.get_mcs_as_json(molList, JSON.stringify({ RingMatchesRingOnly: true, CompleteRingsOnly: true, BondCompare: 'Any', AtomCompare: 'Any', Timeout: 1, })); } finally { if (molList) { molList.delete(); } } assert(mcs); mcs = JSON.parse(mcs); assert(mcs.canceled); } { const smiArray = [ "Nc1ccc(cc1)C-Cc1c(N)cccc1", "Nc1ccc(cc1)C=Cc1c(N)cccc1", ]; let molList; let mcs; try { molList = molListFromSmiArray(smiArray); mcs = RDKitModule.get_mcs_as_json(molList); } finally { if (molList) { molList.delete(); } } assert(mcs); mcs = JSON.parse(mcs); assert(!mcs.canceled); assert(!Array.isArray(mcs.smarts)); assert.equal(mcs.numAtoms, 8); assert.equal(mcs.numBonds, 8); assert(mcs.smarts === '[#7]-[#6]1:[#6]:[#6]:[#6](:[#6]:[#6]:1)-[#6]'); try { molList = molListFromSmiArray(smiArray); mcs = RDKitModule.get_mcs_as_json(molList, JSON.stringify({StoreAll: true})); } finally { if (molList) { molList.delete(); } } assert(mcs); mcs = JSON.parse(mcs); assert(!mcs.canceled); assert(Array.isArray(mcs.smarts)); assert.equal(mcs.numAtoms, 8); assert.equal(mcs.numBonds, 8); assert.equal(mcs.smarts.length, 2); assert(mcs.smarts.includes('[#6]-[#6]1:[#6]:[#6]:[#6]:[#6]:[#6]:1-[#7]')); assert(mcs.smarts.includes('[#7]-[#6]1:[#6]:[#6]:[#6](:[#6]:[#6]:1)-[#6]')); } { const smiArray = [ "C1CC1", "c1ccccc1", ]; let molList; let mcs; try { molList = molListFromSmiArray(smiArray); mcs = RDKitModule.get_mcs_as_json(molList, JSON.stringify({ CompleteRingsOnly: true })); } finally { if (molList) { molList.delete(); } } assert(mcs); mcs = JSON.parse(mcs); assert(!mcs.canceled); assert(!mcs.numAtoms); assert(!mcs.numBonds); assert(!mcs.smarts); try { molList = molListFromSmiArray(smiArray); mcs = RDKitModule.get_mcs_as_json(molList, JSON.stringify({ CompleteRingsOnly: true, StoreAll: true })); } finally { if (molList) { molList.delete(); } } assert(mcs); mcs = JSON.parse(mcs); assert(!mcs.canceled); assert(!mcs.numAtoms); assert(!mcs.numBonds); assert(!mcs.smarts.length); } } function test_get_num_atoms_bonds() { var mol = RDKitModule.get_mol('CCCC'); var molH = RDKitModule.get_mol_copy(mol); molH.add_hs_in_place(); assert.equal(mol.get_num_atoms(), molH.get_num_atoms(true)); assert.equal(mol.get_num_atoms(), 4); assert.equal(molH.get_num_atoms(), 14); assert.equal(molH.get_num_atoms(false), 14); assert.equal(mol.get_num_bonds(), 3); assert.equal(molH.get_num_bonds(), 13); } function test_sanitize_no_kekulize_no_setaromaticity() { var molblock1 = ` RDKit 2D 6 6 0 0 0 0 0 0 0 0999 V2000 1.5000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.5000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.7500 1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.7500 1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1 2 2 0 2 3 1 0 3 4 2 0 4 5 1 0 5 6 2 0 6 1 1 0 M END`; var molblock2 = ` RDKit 2D 6 6 0 0 0 0 0 0 0 0999 V2000 1.5000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.5000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.7500 1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.7500 1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 0 2 3 2 0 3 4 1 0 4 5 2 0 5 6 1 0 6 1 2 0 M END`; var mol1 = RDKitModule.get_mol(molblock1, JSON.stringify({kekulize: false, setAromaticity: false})); var mol2 = RDKitModule.get_mol(molblock2, JSON.stringify({kekulize: false, setAromaticity: false})); assert.notEqual(mol1.get_molblock(), mol2.get_molblock()); mol1.delete(); mol2.delete(); mol1 = RDKitModule.get_mol(molblock1); mol2 = RDKitModule.get_mol(molblock2); assert.equal(mol1.get_molblock(), mol2.get_molblock()); mol1.delete(); mol2.delete(); } function test_partial_sanitization() { var mol1 = RDKitModule.get_mol('C1CCC2CCCC2C1', JSON.stringify({ sanitize: false, removeHs: false, assignStereo: false, })); var fp1 = mol1.get_morgan_fp(JSON.stringify({radius: 2, nBits: 32})); assert.equal(fp1, '00001001010101000000100000110010'); mol1.delete(); var mol2 = RDKitModule.get_mol('C1CCC2CCCC2C1', JSON.stringify({ sanitize: false, removeHs: false, assignStereo: false, fastFindRings: false })); var exceptionThrown = false; try { mol2.get_morgan_fp(JSON.stringify({radius: 2, nBits: 32})); } catch (e) { exceptionThrown = true; } assert(exceptionThrown); mol2.delete(); let mb; mol1 = RDKitModule.get_mol('c1ccccc1N(=O)=O', JSON.stringify({sanitize: false})); mb = mol1.get_molblock(JSON.stringify({kekulize: false})); assert(mb.includes(' 1 2 4 0')); assert(mb.includes(' 7 8 2 0') && mb.includes(' 7 9 2 0')); assert(!mb.includes('M CHG')); mol1.delete(); mol1 = RDKitModule.get_mol('c1ccccc1N(=O)=O', JSON.stringify({sanitize: {SANITIZE_CLEANUP: true}})); mb = mol1.get_molblock(JSON.stringify({kekulize: false})); assert(mb.includes(' 1 2 4 0')); assert((mb.includes(' 7 8 1 0') && mb.includes(' 7 9 2 0')) || (mb.includes(' 7 8 2 0') && mb.includes(' 7 9 1 0'))); assert(mb.includes('M CHG 2')); mol1.delete(); mol1 = RDKitModule.get_mol('c1ccccc1N(=O)=O', JSON.stringify({sanitize: { SANITIZE_CLEANUP: true, SANITIZE_KEKULIZE: true }})); mb = mol1.get_molblock(JSON.stringify({kekulize: false})); assert(!mb.includes(' 1 2 4 0')); assert((mb.includes(' 7 8 1 0') && mb.includes(' 7 9 2 0')) || (mb.includes(' 7 8 2 0') && mb.includes(' 7 9 1 0'))); assert(mb.includes('M CHG 2')); mol1.delete(); } function captureStdoutStderr(stdoutCallback, optStderrCallback) { if (!stdoutCallback) { return null; } const stderrCallback = optStderrCallback || stdoutCallback; const origStdoutWrite = process.stdout.write; const origStderrWrite = process.stderr.write; process.stdout.write = (chunk) => stdoutCallback(chunk); process.stderr.write = (chunk) => stderrCallback(chunk); return () => { process.stdout.write = origStdoutWrite; process.stderr.write = origStderrWrite; }; } function captureStdoutStderr(stdoutCallback, optStderrCallback) { if (!stdoutCallback) { return null; } const stderrCallback = optStderrCallback || stdoutCallback; const origStdoutWrite = process.stdout.write; const origStderrWrite = process.stderr.write; process.stdout.write = (chunk) => stdoutCallback(chunk); process.stderr.write = (chunk) => stderrCallback(chunk); return () => { process.stdout.write = origStdoutWrite; process.stderr.write = origStderrWrite; }; } function test_capture_logs() { const PENTAVALENT_CARBON = 'CC(C)(C)(C)C'; const PENTAVALENT_CARBON_VALENCE_ERROR = 'Explicit valence for atom # 1 C, 5, is greater than permitted'; const TETRAVALENT_NITROGEN = 'CN(C)(C)C'; const TETRAVALENT_NITROGEN_VALENCE_ERROR = 'Explicit valence for atom # 1 N, 4, is greater than permitted'; RDKitModule.disable_logging(); assert(!RDKitModule.enable_logging('dummy')); assert(RDKitModule.enable_logging('rdApp.info')); var restoreStreams; var captureHasHappened; // Should see no warning on pentavalent carbon below captureHasHappened = false; restoreStreams = captureStdoutStderr((capturedStreams) => { captureHasHappened = true; }); assert(restoreStreams); try { var mol = RDKitModule.get_mol(PENTAVALENT_CARBON); assert(!mol); } finally { restoreStreams(); } assert(!captureHasHappened); RDKitModule.enable_logging("rdApp.error"); // Should see warning on pentavalent carbon below restoreStreams = captureStdoutStderr((capturedStreams) => { captureHasHappened = true; assert(capturedStreams.includes(PENTAVALENT_CARBON_VALENCE_ERROR)); }); assert(restoreStreams); try { var mol = RDKitModule.get_mol(PENTAVALENT_CARBON); assert(!mol); } finally { restoreStreams(); } assert(captureHasHappened); captureHasHappened = false; RDKitModule.disable_logging(); // Should again see no warning on pentavalent carbon below restoreStreams = captureStdoutStderr((capturedStreams) => { captureHasHappened = true; }); assert(restoreStreams); try { var mol = RDKitModule.get_mol(PENTAVALENT_CARBON); assert(!mol); } finally { restoreStreams(); } assert(!captureHasHappened); var logHandle1; var logHandle2; var logBuffer1; var mol; ['set_log_tee', 'set_log_capture'].forEach((func, i) => { logHandle1 = RDKitModule[func]('rdApp.*'); assert(logHandle1); logBuffer1 = logHandle1.get_buffer(); assert(!logBuffer1); restoreStreams = captureStdoutStderr((capturedStreams) => { captureHasHappened = true; assert(capturedStreams.includes(TETRAVALENT_NITROGEN_VALENCE_ERROR)); }); assert(restoreStreams); try { mol = RDKitModule.get_mol(TETRAVALENT_NITROGEN); assert(!mol); } finally { restoreStreams(); } assert(!((func === 'set_log_tee') ^ captureHasHappened)); captureHasHappened = false; logBuffer1 = logHandle1.get_buffer(); assert(logBuffer1); assert(logBuffer1.includes(TETRAVALENT_NITROGEN_VALENCE_ERROR)); logHandle1.clear_buffer(); assert(!logHandle1.get_buffer()); logHandle2 = RDKitModule[func]('rdApp.*'); assert(!logHandle2); restoreStreams = captureStdoutStderr((capturedStreams) => { captureHasHappened = true; assert(capturedStreams.includes(PENTAVALENT_CARBON_VALENCE_ERROR)); }); assert(restoreStreams); try { mol = RDKitModule.get_mol(PENTAVALENT_CARBON); assert(!mol); } finally { restoreStreams(); } assert(!((func === 'set_log_tee') ^ captureHasHappened)); captureHasHappened = false; logBuffer1 = logHandle1.get_buffer(); assert(logBuffer1); assert(logBuffer1.includes(PENTAVALENT_CARBON_VALENCE_ERROR)); assert(!logBuffer1.includes(TETRAVALENT_NITROGEN_VALENCE_ERROR)); logHandle1.delete(); logHandle2 = RDKitModule[func]('rdApp.*'); assert(logHandle2); logHandle2.delete(); }) // Should again see no warning on pentavalent carbon below restoreStreams = captureStdoutStderr((capturedStreams) => { captureHasHappened = true; }); assert(restoreStreams); try { var mol = RDKitModule.get_mol(PENTAVALENT_CARBON); assert(!mol); } finally { restoreStreams(); } assert(!captureHasHappened); } function test_rgroup_match_heavy_hydro_none_charged() { var templateRef = RDKitModule.get_mol(` MJ201100 7 7 0 0 0 0 0 0 0 0999 V2000 -0.5804 1.2045 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.2948 0.7920 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.2948 -0.0330 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.5804 -0.4455 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.1340 -0.0330 0.0000 A 0 0 0 0 0 0 0 0 0 0 0 0 0.1340 0.7920 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.8485 -0.4455 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0 1 2 2 0 0 0 0 2 3 1 0 0 0 0 3 4 2 0 0 0 0 6 1 1 0 0 0 0 4 5 1 0 0 0 0 5 6 2 0 0 0 0 5 7 1 0 0 0 0 M RGP 1 7 1 M END `); assert(templateRef); var mol; var allowRGroups = true; [true, false].forEach((alignOnly) => { mol = RDKitModule.get_mol("Cc1ccccc1"); assert(mol); assert.equal(mol.get_num_atoms(), 7); assert.equal(JSON.parse(mol.generate_aligned_coords(templateRef, JSON.stringify({ allowRGroups, alignOnly }))).atoms.length, 7); mol.delete(); mol = RDKitModule.get_mol("c1ccccc1"); assert(mol); assert.equal(mol.get_num_atoms(), 6); assert.equal(JSON.parse(mol.generate_aligned_coords(templateRef, JSON.stringify({ allowRGroups, alignOnly }))).atoms.length, 6); mol.delete(); mol = RDKitModule.get_mol("[H]c1ccccc1", JSON.stringify({removeHs: false})); assert(mol); assert.equal(mol.get_num_atoms(), 7); assert.equal(JSON.parse(mol.generate_aligned_coords(templateRef, JSON.stringify({ allowRGroups, alignOnly }))).atoms.length, 7); mol.delete(); mol = RDKitModule.get_mol("n1ccccc1"); assert(mol); assert.equal(mol.get_num_atoms(), 6); assert.equal(JSON.parse(mol.generate_aligned_coords(templateRef, JSON.stringify({ allowRGroups, alignOnly }))).atoms.length, 6); mol.delete(); mol = RDKitModule.get_mol("C[n+]1ccccc1"); assert(mol); assert.equal(mol.get_num_atoms(), 7); assert.equal(JSON.parse(mol.generate_aligned_coords(templateRef, JSON.stringify({ allowRGroups, alignOnly }))).atoms.length, 7); mol.delete(); }); templateRef.delete(); } function test_get_sss_json() { var fentanylScaffold = RDKitModule.get_mol(` MJ201100 25 27 0 0 0 0 0 0 0 0999 V2000 -0.3910 -1.2720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.2160 -1.2721 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.6285 -1.9866 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.2161 -2.7010 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.3911 -2.7011 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.0214 -1.9865 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.0213 -0.5575 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 -0.3911 0.1568 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.0213 0.8713 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.3911 1.5859 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.2161 1.5858 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 -1.6287 0.8714 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.2161 0.1568 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.6286 2.3002 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.8463 -0.5575 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1.2588 0.1569 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 -2.4536 2.3002 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.8661 1.5858 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -3.6910 1.5858 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -4.1036 0.8712 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -3.6912 0.1568 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.8662 0.1567 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.4536 0.8713 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1.2589 -1.2720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.0839 -1.2719 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1 2 2 0 0 0 0 2 3 1 0 0 0 0 3 4 2 0 0 0 0 4 5 1 0 0 0 0 5 6 2 0 0 0 0 6 1 1 0 0 0 0 9 10 1 0 0 0 0 12 13 1 0 0 0 0 8 9 1 0 0 0 0 8 13 1 0 0 0 0 10 11 1 0 0 0 0 11 12 1 0 0 0 0 11 14 1 0 0 0 0 1 7 1 0 0 0 0 7 8 1 0 0 0 0 7 15 1 0 0 0 0 14 17 1 0 0 0 0 17 18 1 0 0 0 0 19 20 1 0 0 0 0 20 21 2 0 0 0 0 21 22 1 0 0 0 0 22 23 2 0 0 0 0 18 19 2 0 0 0 0 23 18 1 0 0 0 0 15 24 1 0 0 0 0 24 25 1 0 0 0 0 15 16 2 0 0 0 0 M END `); var bilastine = RDKitModule.get_mol("O=C(O)C(c1ccc(cc1)CCN4CCC(c2nc3ccccc3n2CCOCC)CC4)(C)C"); var referenceSmarts = "c1ccccc1CCN1CCCCC1"; var res = bilastine.generate_aligned_coords(fentanylScaffold, JSON.stringify({useCoordGen: true, referenceSmarts})); assert(res); var resExpected = "{\"atoms\":[6,5,4,9,8,7,10,11,12,13,14,15,30,31],\"bonds\":[13,30,14,29,12,36,11,10,9,5,4,33,8,6,7]}"; assert.equal(res, resExpected); assert.equal(JSON.parse(res).bonds.length, 15); bilastine.delete(); fentanylScaffold.delete(); } function test_relabel_mapped_dummies() { var core = RDKitModule.get_mol("c1cc([4*:2])c([3*:1])cn1"); assert.equal(core.get_cxsmiles(), "c1cc([4*:2])c([3*:1])cn1"); core.delete(); core = RDKitModule.get_mol("c1cc([4*:2])c([3*:1])cn1", JSON.stringify({mappedDummiesAreRGroups: true})); assert.equal(core.get_cxsmiles(), "*c1ccncc1* |atomProp:0.dummyLabel.R2:7.dummyLabel.R1|"); core.delete(); } function test_assign_cip_labels() { var origSetting; const getTextSection = (svg) => ( svg.split('\n').map((line) => line.replace(/^([^<]*)<\/text>$/, '$1')).join('') ); try { origSetting = RDKitModule.use_legacy_stereo_perception(true); { var mol = RDKitModule.get_mol('C/C=C/c1ccccc1[S@@](C)=O'); var svg = mol.get_svg_with_highlights(JSON.stringify({noFreetype: true, addStereoAnnotation: true})); assert(getTextSection(svg).includes("(S)")); assert(!getTextSection(svg).includes("(R)")); mol.delete(); } RDKitModule.use_legacy_stereo_perception(false); { var mol = RDKitModule.get_mol('C/C=C/c1ccccc1[S@@](C)=O'); var svg = mol.get_svg_with_highlights(JSON.stringify({noFreetype: true, addStereoAnnotation: true})); assert(!getTextSection(svg).includes("(S)")); assert(!getTextSection(svg).includes("(R)")); mol.delete(); } { var mol = RDKitModule.get_mol('C/C=C/c1ccccc1[S@@](C)=O', JSON.stringify({assignCIPLabels: true})); var svg = mol.get_svg_with_highlights(JSON.stringify({noFreetype: true, addStereoAnnotation: true})); assert(!getTextSection(svg).includes("(S)")); assert(getTextSection(svg).includes("(R)")); mol.delete(); } } finally { RDKitModule.use_legacy_stereo_perception(origSetting); } } function test_smiles_smarts_params() { { const amoxicillinPubChem = 'CC1([C@@H](N2[C@H](S1)[C@@H](C2=O)NC(=O)[C@@H](C3=CC=C(C=C3)O)N)C(=O)O)C'; const mol = RDKitModule.get_mol(amoxicillinPubChem); { const canonicalSmiles = mol.get_smiles(); assert(canonicalSmiles === 'CC1(C)S[C@@H]2[C@H](NC(=O)[C@H](N)c3ccc(O)cc3)C(=O)N2[C@H]1C(=O)O'); } ['{}', ''].forEach((emptyJson) => { const canonicalSmiles = mol.get_smiles(emptyJson); assert(canonicalSmiles === 'CC1(C)S[C@@H]2[C@H](NC(=O)[C@H](N)c3ccc(O)cc3)C(=O)N2[C@H]1C(=O)O'); }); const nonCanonicalSmiles = mol.get_smiles(JSON.stringify({canonical: false})); assert(nonCanonicalSmiles === 'CC1(C)[C@H](C(=O)O)N2[C@H](S1)[C@H](NC(=O)[C@@H](c1ccc(O)cc1)N)C2=O'); const canonicalSmilesNoStereo = mol.get_smiles(JSON.stringify({doIsomericSmiles: false})); assert(canonicalSmilesNoStereo === 'CC1(C)SC2C(NC(=O)C(N)c3ccc(O)cc3)C(=O)N2C1C(=O)O'); const nonCanonicalSmilesNoStereo = mol.get_smiles(JSON.stringify({doIsomericSmiles: false, canonical: false})); assert(nonCanonicalSmilesNoStereo === 'CC1(C)C(C(=O)O)N2C(S1)C(NC(=O)C(c1ccc(O)cc1)N)C2=O'); mol.delete(); } { const bicyclo221heptane = ` RDKit 2D 9 10 0 0 1 0 0 0 0 0999 V2000 -2.8237 -1.3088 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 -1.5723 -0.3996 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.5723 1.1473 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.1011 1.6253 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1.3701 1.1474 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1.3701 -0.3995 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.6217 -1.3087 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 -0.1009 -0.8775 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.8083 0.3739 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2 1 1 1 2 3 1 0 4 3 1 0 4 5 1 0 6 5 1 0 6 7 1 1 6 8 1 0 8 9 1 1 8 2 1 0 4 9 1 1 M END `; const mol = RDKitModule.get_mol(bicyclo221heptane); { const canonicalCXSmiles = mol.get_cxsmiles(); const [_, canonicalSmiles, wedging] = canonicalCXSmiles.match(/^(\S+) \|\([^\)]+\),([^\|]+)\|$/); assert(canonicalSmiles === 'N[C@@H]1C[C@@H]2C[C@H]1[C@@H](O)C2'); assert(wedging === 'wD:3.9,wU:1.0,5.4,6.7'); } ['{}', ''].forEach((emptyJson) => { const canonicalCXSmiles = mol.get_cxsmiles(emptyJson); const [_, canonicalSmiles, wedging] = canonicalCXSmiles.match(/^(\S+) \|\([^\)]+\),([^\|]+)\|$/); assert(canonicalSmiles === 'N[C@@H]1C[C@@H]2C[C@H]1[C@@H](O)C2'); assert(wedging === 'wD:3.9,wU:1.0,5.4,6.7'); }); { const canonicalCXSmiles = mol.get_cxsmiles(JSON.stringify({restoreBondDirOption: 'RestoreBondDirOptionTrue'})); const [_, canonicalSmiles, wedging] = canonicalCXSmiles.match(/^(\S+) \|\([^\)]+\),([^\|]+)\|$/); assert(canonicalSmiles === 'N[C@@H]1C[C@@H]2C[C@H]1[C@@H](O)C2'); assert(wedging === 'wU:1.0,3.3,5.4,6.7'); } { const nonCanonicalCXSmilesNoStereo = mol.get_cxsmiles(JSON.stringify({doIsomericSmiles: false, canonical: false, CX_ALL_BUT_COORDS: true})); assert(nonCanonicalCXSmilesNoStereo === 'OC1CC2CC(N)C1C2'); const nonCanonicalCXSmilesNoStereoAtomProp = `${nonCanonicalCXSmilesNoStereo} |atomProp:1.atomProp.1.234|`; const molWithAtomProp = RDKitModule.get_mol(nonCanonicalCXSmilesNoStereoAtomProp); assert(molWithAtomProp); const cxSmilesWithAtomProp = molWithAtomProp.get_cxsmiles(JSON.stringify({CX_ALL_BUT_COORDS: true})); assert(cxSmilesWithAtomProp === 'NC1CC2CC(O)C1C2 |atomProp:5.atomProp.1.234|'); molWithAtomProp.delete(); } mol.delete(); } { const chiralQuery = RDKitModule.get_qmol('N-[C@H](-C(-O)=O)-C(-C)-C'); assert(chiralQuery.get_smarts() === 'N-[C@&H1](-C(-O)=O)-C(-C)-C'); ['', '{}'].forEach((emptyJson) => { assert(chiralQuery.get_smarts(emptyJson) === 'N-[C@&H1](-C(-O)=O)-C(-C)-C'); }); assert(chiralQuery.get_smarts(JSON.stringify({doIsomericSmiles: false})) === 'N-[C&H1](-C(-O)=O)-C(-C)-C'); } { const chiralQuery = RDKitModule.get_qmol('N-[C@H](-C(-O)=O)-C(-C)-C |atomProp:1.atomProp.1.234|'); assert(chiralQuery.get_cxsmarts() === 'N-[C@&H1](-C(-O)=O)-C(-C)-C |atomProp:1.atomProp.1.234|'); ['', '{}'].forEach((emptyJson) => { assert(chiralQuery.get_cxsmarts(emptyJson) === 'N-[C@&H1](-C(-O)=O)-C(-C)-C |atomProp:1.atomProp.1.234|'); }); assert(chiralQuery.get_cxsmarts(JSON.stringify({doIsomericSmiles: false})) === 'N-[C&H1](-C(-O)=O)-C(-C)-C |atomProp:1.atomProp.1.234|'); } } function test_wedged_bond_atropisomer() { var atropisomer = ` Mrv2311 05242408162D 0 0 0 0 0 999 V3000 M V30 BEGIN CTAB M V30 COUNTS 14 15 0 0 0 M V30 BEGIN ATOM M V30 1 C 2.0006 -1.54 0 0 M V30 2 N 2.0006 -3.08 0 0 M V30 3 C 0.6669 -3.85 0 0 M V30 4 C -0.6668 -3.08 0 0 M V30 5 C -0.6668 -1.54 0 0 M V30 6 C -2.0006 -0.77 0 0 M V30 7 C 0.6669 -0.77 0 0 M V30 8 C 0.6669 0.77 0 0 M V30 9 C -0.6668 1.54 0 0 M V30 10 C -2.0006 0.77 0 0 M V30 11 C -0.6668 3.08 0 0 M V30 12 C 0.6669 3.85 0 0 M V30 13 C 2.0006 3.08 0 0 M V30 14 C 2.0006 1.54 0 0 M V30 END ATOM M V30 BEGIN BOND M V30 1 1 1 2 M V30 2 2 2 3 M V30 3 1 3 4 M V30 4 2 4 5 M V30 5 1 5 6 M V30 6 1 7 5 CFG=3 M V30 7 2 7 1 M V30 8 1 7 8 M V30 9 2 8 9 M V30 10 1 9 10 M V30 11 1 9 11 M V30 12 2 11 12 M V30 13 1 12 13 M V30 14 2 13 14 M V30 15 1 8 14 M V30 END BOND M V30 END CTAB M END `; var mol = RDKitModule.get_mol(atropisomer); assert(mol); var svg = mol.get_svg_with_highlights(JSON.stringify({ useMolBlockWedging: true, noFreetype: true })); assert(svg.match(//g).length > 6); assert(!svg.match(//g)); mol.delete(); } function test_get_molblock_use_molblock_wedging() { var mb = ` RDKit 2D 9 10 0 0 1 0 0 0 0 0999 V2000 1.4885 -4.5513 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 2.0405 -3.9382 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.8610 -4.0244 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 3.1965 -3.2707 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 3.0250 -2.4637 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.2045 -2.3775 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1.7920 -1.6630 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 1.8690 -3.1311 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.5834 -2.7186 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2 1 1 1 2 3 1 0 4 3 1 0 4 5 1 0 6 5 1 0 6 7 1 1 6 8 1 0 8 9 1 1 8 2 1 0 4 9 1 1 M END `; var mol = RDKitModule.get_mol(mb); assert(mol); var molCopy = RDKitModule.get_mol_copy(mol); assert(molCopy); var mbRDKitWedging = mol.get_molblock(); assert(mbRDKitWedging !== mb); var mbOrigWedging = mol.get_molblock(JSON.stringify({useMolBlockWedging: true})); assert(mb === mbOrigWedging); var mbRDKitWedgingPostOrig = mol.get_molblock(); assert(mb !== mbRDKitWedgingPostOrig); assert(mbRDKitWedging === mbRDKitWedgingPostOrig); mol.delete(); } function test_assign_chiral_tags_from_mol_parity() { let mol; const artemisininCTAB = `68827 -OEChem-03262404452D 20 23 0 1 0 0 0 0 0999 V2000 4.3177 0.4203 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 5.7899 1.1100 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 6.4870 -0.3207 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 4.5402 1.3953 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 7.4004 -1.8275 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 4.6664 -0.2988 0.0000 C 0 0 2 0 0 0 0 0 0 0 0 0 3.7655 0.1351 0.0000 C 0 0 2 0 0 0 0 0 0 0 0 0 4.7603 -1.3362 0.0000 C 0 0 1 0 0 0 0 0 0 0 0 0 2.8959 -0.4383 0.0000 C 0 0 1 0 0 0 0 0 0 0 0 0 5.5674 0.1351 0.0000 C 0 0 1 0 0 0 0 0 0 0 0 0 3.9042 -1.9296 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 3.5430 1.1100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.9657 -1.4776 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 5.6389 -1.8668 0.0000 C 0 0 2 0 0 0 0 0 0 0 0 0 5.1664 1.8919 0.0000 C 0 0 2 0 0 0 0 0 0 0 0 0 4.1664 1.8919 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.0000 0.0059 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 6.5237 -1.3465 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 5.6330 -2.8668 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 5.3890 2.8668 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1 4 1 0 0 0 0 6 1 1 0 0 0 0 2 10 1 0 0 0 0 2 15 1 0 0 0 0 3 10 1 0 0 0 0 3 18 1 0 0 0 0 4 15 1 0 0 0 0 5 18 2 0 0 0 0 6 7 1 0 0 0 0 6 8 1 0 0 0 0 6 10 1 0 0 0 0 7 9 1 0 0 0 0 7 12 1 0 0 0 0 8 11 1 0 0 0 0 8 14 1 0 0 0 0 9 13 1 0 0 0 0 9 17 1 0 0 0 0 11 13 1 0 0 0 0 12 16 1 0 0 0 0 14 18 1 0 0 0 0 14 19 1 0 0 0 0 15 16 1 0 0 0 0 15 20 1 0 0 0 0 M END `; try { mol = RDKitModule.get_mol(artemisininCTAB); assert(mol); assert(mol.get_smiles() === 'CC1CCC2C(C)C(=O)OC3OC4(C)CCC1C32OO4'); } finally { if (mol) { mol.delete(); } } try { mol = RDKitModule.get_mol(artemisininCTAB, JSON.stringify({ assignChiralTypesFromMolParity: true })); assert(mol); assert(mol.get_smiles() === 'C[C@@H]1CC[C@H]2[C@@H](C)C(=O)O[C@@H]3O[C@@]4(C)CC[C@@H]1[C@]32OO4'); } finally { if (mol) { mol.delete(); } } } function test_make_dummies_queries() { let mol; let query; let match; try { mol = RDKitModule.get_mol('CN'); assert(mol); query = RDKitModule.get_mol('*N'); assert(query); match = JSON.parse(mol.get_substruct_match(query)); assert(!match.atoms); query.delete(); query = RDKitModule.get_mol('*N', JSON.stringify(({ makeDummiesQueries: true }))); assert(query); match = JSON.parse(mol.get_substruct_match(query)); assert(match.atoms.toString() === [0, 1].toString()); } finally { if (mol) { mol.delete(); } if (query) { query.delete(); } } } function test_get_mol_copy() { let mol; let mol_copy1; let mol_copy2; try { mol = RDKitModule.get_mol('c1ccccn1'); assert(mol); mol_copy1 = RDKitModule.get_mol_copy(mol); assert(mol_copy1); mol_copy2 = mol.copy(); assert(mol_copy2); assert(mol.get_molblock() === mol_copy1.get_molblock()); assert(mol.get_molblock() === mol_copy2.get_molblock()); } finally { if (mol) { mol.delete(); } if (mol_copy1) { mol_copy1.delete(); } if (mol_copy2) { mol_copy2.delete(); } } } function test_multi_highlights() { const mol = RDKitModule.get_mol('[H]c1cc2c(-c3ccnc(Nc4ccc(F)c(F)c4)n3)c(-c3cccc(C(F)(F)F)c3)nn2nc1C', JSON.stringify({removeHs: false})); const details = '{"width":250,"height":200,"highlightAtomMultipleColors":{"15":[[0.941,0.894,0.259]],"17":[[0,0.62,0.451]],"21":[[0.902,0.624,0]],"22":[[0.902,0.624,0]],"23":[[0.902,0.624,0]],"24":[[0.902,0.624,0]],"25":[[0.902,0.624,0]],"26":[[0.902,0.624,0]],"27":[[0.902,0.624,0]],"28":[[0.902,0.624,0]],"29":[[0.902,0.624,0]],"30":[[0.902,0.624,0]],"35":[[0.337,0.706,0.914]]},"highlightBondMultipleColors":{"14":[[0.941,0.894,0.259]],"16":[[0,0.62,0.451]],"20":[[0.902,0.624,0]],"21":[[0.902,0.624,0]],"22":[[0.902,0.624,0]],"23":[[0.902,0.624,0]],"24":[[0.902,0.624,0]],"25":[[0.902,0.624,0]],"26":[[0.902,0.624,0]],"27":[[0.902,0.624,0]],"28":[[0.902,0.624,0]],"29":[[0.902,0.624,0]],"34":[[0.337,0.706,0.914]],"38":[[0.902,0.624,0]]},"highlightAtomRadii":{"15":0.4,"17":0.4,"21":0.4,"22":0.4,"23":0.4,"24":0.4,"25":0.4,"26":0.4,"27":0.4,"28":0.4,"29":0.4,"30":0.4,"35":0.4},"highlightLineWidthMultipliers":{"14":2,"16":2,"20":2,"21":2,"22":2,"23":2,"24":2,"25":2,"26":2,"27":2,"28":2,"29":2,"34":2,"38":2}}'; const svgWithDetails = mol.get_svg_with_highlights(details); assert(svgWithDetails.includes('ellipse')); const COLORS = ['#009E73', '#55B4E9', '#E69F00', '#EFE342']; assert(COLORS.every((color) => svgWithDetails.includes(color))); const svgWithOutDetails = mol.get_svg_with_highlights(''); assert(!svgWithOutDetails.includes('ellipse')); assert(!COLORS.some((color) => svgWithOutDetails.includes(color))); mol.delete(); } const getFoundRgdRowAsMap = (row, keep) => Object.fromEntries(Object.entries(row).map(([rlabel, mol]) => { try { assert(mol); assert(mol instanceof RDKitModule.Mol); const smi = mol.get_smiles(); return [rlabel, smi]; } finally { if (!keep && mol) { mol.delete(); } } })); const getExpectedRgdRowAsMap = (row) => Object.fromEntries(row.split(' ').map((rgroup) => { const match = rgroup.match(/^([^:]+):(.+)$/); assert(match); return match.slice(1); })); const getExpectedRgdAsCols = (rowArray) => { const res = {}; rowArray.forEach((row, i) => { const rgroupToSmiMap = getExpectedRgdRowAsMap(row); Object.entries(rgroupToSmiMap).forEach(([rlabel, smi]) => { if (!i) { res[rlabel] = []; } const arr = res[rlabel]; assert(Array.isArray(arr)); arr.push(smi); }); }); return res; }; function test_singlecore_rgd() { const ringData3 = ['c1cocc1CCl', 'c1c[nH]cc1CI', 'c1cscc1CF']; const expectedRingData3Rgd = ['Core:c1cc([*:1])co1 R1:ClC[*:1]', 'Core:c1cc([*:1])c[nH]1 R1:IC[*:1]', 'Core:c1cc([*:1])cs1 R1:FC[*:1]']; const expectedRingData3RgdAsCols = getExpectedRgdAsCols(expectedRingData3Rgd); const core = RDKitModule.get_qmol('*1***[*:1]1'); assert(core); try { const scoreMethods = ['Match', 'FingerprintVariance']; scoreMethods.forEach((scoreMethod) => { const params = { scoreMethod, allowNonTerminalRGroups: true, }; const rgd = RDKitModule.get_rgd(core, JSON.stringify(params)); ringData3.forEach((ringData, i) => { const mol = RDKitModule.get_mol(ringData); assert(mol); try { const res = rgd.add(mol); assert(res === i); } finally { mol.delete(); } }); rgd.process(); const rows = rgd.get_rgroups_as_rows(); assert(Array.isArray(rows)); assert(rows.length === ringData3.length); rows.forEach((row, i) => { const expectedRowMapping = getExpectedRgdRowAsMap(expectedRingData3Rgd[i]); const foundMapping = getFoundRgdRowAsMap(row); assert(Object.keys(foundMapping).length === Object.keys(expectedRowMapping).length); Object.entries(foundMapping).forEach(([rlabel, smi]) => { assert(expectedRowMapping[rlabel] && expectedRowMapping[rlabel] === smi); }); }) const cols = rgd.get_rgroups_as_columns(); assert(typeof cols === 'object'); assert(Object.keys(cols).length === Object.keys(expectedRingData3RgdAsCols).length); Object.keys(cols).forEach((rlabel) => { const expectedRGroupsAsSmiles = expectedRingData3RgdAsCols[rlabel]; assert(Array.isArray(expectedRGroupsAsSmiles)); const rgroupsAsMolList = cols[rlabel]; assert(rgroupsAsMolList); assert(rgroupsAsMolList instanceof RDKitModule.MolList); try { assert(expectedRGroupsAsSmiles.length === rgroupsAsMolList.size()); let i = 0; while (!rgroupsAsMolList.at_end()) { const mol = rgroupsAsMolList.next(); assert(mol); try { assert(mol.get_smiles() === expectedRGroupsAsSmiles[i++]); } finally { mol.delete(); } } } finally { rgroupsAsMolList.delete(); } }); }); } finally { core.delete(); } } function test_multicore_rgd() { const smiArray = [ 'C1CCNC(Cl)CC1', 'C1CC(Cl)NCCC1', 'C1CCNC(I)CC1', 'C1CC(I)NCCC1', 'C1CCSC(Cl)CC1', 'C1CC(Cl)SCCC1', 'C1CCSC(I)CC1', 'C1CC(I)SCCC1', 'C1CCOC(Cl)CC1', 'C1CC(Cl)OCCC1', 'C1CCOC(I)CC1', 'C1CC(I)OCCC1' ]; const expectedRgd = [ 'Core:C1CCNC([*:1])CC1 R1:Cl[*:1]', 'Core:C1CCNC([*:1])CC1 R1:Cl[*:1]', 'Core:C1CCNC([*:1])CC1 R1:I[*:1]', 'Core:C1CCNC([*:1])CC1 R1:I[*:1]', 'Core:C1CCSC([*:1])CC1 R1:Cl[*:1]', 'Core:C1CCSC([*:1])CC1 R1:Cl[*:1]', 'Core:C1CCSC([*:1])CC1 R1:I[*:1]', 'Core:C1CCSC([*:1])CC1 R1:I[*:1]', 'Core:C1CCOC([*:1])CC1 R1:Cl[*:1]', 'Core:C1CCOC([*:1])CC1 R1:Cl[*:1]', 'Core:C1CCOC([*:1])CC1 R1:I[*:1]', 'Core:C1CCOC([*:1])CC1 R1:I[*:1]' ]; const expectedRgdAsCols = getExpectedRgdAsCols(expectedRgd); const cores = molListFromSmiArray(['C1CCNCCC1', 'C1CCOCCC1', 'C1CCSCCC1']); try { const rgd = RDKitModule.get_rgd(cores); smiArray.forEach((smi, i) => { const mol = RDKitModule.get_mol(smi); assert(mol); try { assert(rgd.add(mol) === i); } finally { mol.delete(); } }); assert(rgd.process()); const rows = rgd.get_rgroups_as_rows(); assert(Array.isArray(rows)); assert(rows.length === smiArray.length); rows.forEach((row, i) => { const expectedRowMapping = getExpectedRgdRowAsMap(expectedRgd[i]); const foundMapping = getFoundRgdRowAsMap(row); assert(Object.keys(foundMapping).length === Object.keys(expectedRowMapping).length); Object.entries(foundMapping).forEach(([rlabel, smi]) => { assert(expectedRowMapping[rlabel] && expectedRowMapping[rlabel] === smi); }); }) const cols = rgd.get_rgroups_as_columns(); assert(typeof cols === 'object'); assert(Object.keys(cols).length === Object.keys(expectedRgdAsCols).length); Object.keys(cols).forEach((rlabel) => { const expectedRGroupsAsSmiles = expectedRgdAsCols[rlabel]; assert(Array.isArray(expectedRGroupsAsSmiles)); const rgroupsAsMolList = cols[rlabel]; assert(rgroupsAsMolList); assert(rgroupsAsMolList instanceof RDKitModule.MolList); try { assert(expectedRGroupsAsSmiles.length === rgroupsAsMolList.size()); let i = 0; while (!rgroupsAsMolList.at_end()) { const mol = rgroupsAsMolList.next(); assert(mol); try { assert(mol.get_smiles() === expectedRGroupsAsSmiles[i++]); } finally { mol.delete(); } } } finally { rgroupsAsMolList.delete(); } }); } finally { cores.delete(); } } function test_multi_highlights() { const mol = RDKitModule.get_mol('[H]c1cc2c(-c3ccnc(Nc4ccc(F)c(F)c4)n3)c(-c3cccc(C(F)(F)F)c3)nn2nc1C', JSON.stringify({removeHs: false})); const details = '{"width":250,"height":200,"highlightAtomMultipleColors":{"15":[[0.941,0.894,0.259]],"17":[[0,0.62,0.451]],"21":[[0.902,0.624,0]],"22":[[0.902,0.624,0]],"23":[[0.902,0.624,0]],"24":[[0.902,0.624,0]],"25":[[0.902,0.624,0]],"26":[[0.902,0.624,0]],"27":[[0.902,0.624,0]],"28":[[0.902,0.624,0]],"29":[[0.902,0.624,0]],"30":[[0.902,0.624,0]],"35":[[0.337,0.706,0.914]]},"highlightBondMultipleColors":{"14":[[0.941,0.894,0.259]],"16":[[0,0.62,0.451]],"20":[[0.902,0.624,0]],"21":[[0.902,0.624,0]],"22":[[0.902,0.624,0]],"23":[[0.902,0.624,0]],"24":[[0.902,0.624,0]],"25":[[0.902,0.624,0]],"26":[[0.902,0.624,0]],"27":[[0.902,0.624,0]],"28":[[0.902,0.624,0]],"29":[[0.902,0.624,0]],"34":[[0.337,0.706,0.914]],"38":[[0.902,0.624,0]]},"highlightAtomRadii":{"15":0.4,"17":0.4,"21":0.4,"22":0.4,"23":0.4,"24":0.4,"25":0.4,"26":0.4,"27":0.4,"28":0.4,"29":0.4,"30":0.4,"35":0.4},"highlightLineWidthMultipliers":{"14":2,"16":2,"20":2,"21":2,"22":2,"23":2,"24":2,"25":2,"26":2,"27":2,"28":2,"29":2,"34":2,"38":2}}'; const svgWithDetails = mol.get_svg_with_highlights(details); assert(svgWithDetails.includes('ellipse')); const COLORS = ['#009E73', '#55B4E9', '#E69F00', '#EFE342']; assert(COLORS.every((color) => svgWithDetails.includes(color))); const svgWithOutDetails = mol.get_svg_with_highlights(''); assert(!svgWithOutDetails.includes('ellipse')); assert(!COLORS.some((color) => svgWithOutDetails.includes(color))); mol.delete(); } function test_bw_palette() { const mol = RDKitModule.get_mol('N'); assert(mol); const details = '{"atomColourPalette":"bw"}'; const svgWithDetails = mol.get_svg_with_highlights(details); assert(svgWithDetails.includes('#000000')); assert(!svgWithDetails.includes('#0000FF')); const svgWithoutDetails = mol.get_svg(); assert(!svgWithoutDetails.includes('#000000')); assert(svgWithoutDetails.includes('#0000FF')); mol.delete(); } function test_custom_palette() { const mol = RDKitModule.get_mol('N'); assert(mol); const details = '{"atomColourPalette\":{"7":[1.0,0.0,0.0]}}'; const svgWithDetails = mol.get_svg_with_highlights(details); assert(svgWithDetails.includes('#FF0000')); assert(!svgWithDetails.includes('#0000FF')); const svgWithoutDetails = mol.get_svg(); assert(!svgWithoutDetails.includes('#FF0000')); assert(svgWithoutDetails.includes('#0000FF')); mol.delete(); } function test_pickle() { const mol = RDKitModule.get_mol('c1ccccn1'); assert(mol); mol.set_prop('a', '1'); assert(mol.get_prop('a') === '1'); const pklWithProps = mol.get_as_uint8array(); assert(pklWithProps); let molFromPkl = RDKitModule.get_mol_from_uint8array(pklWithProps); assert(molFromPkl); assert(molFromPkl.has_prop('a')); assert(molFromPkl.get_prop('a') === '1'); molFromPkl.delete(); const pklWithoutProps = mol.get_as_uint8array(JSON.stringify({propertyFlags: { NoProps: true } })); molFromPkl = RDKitModule.get_mol_from_uint8array(pklWithoutProps); assert(molFromPkl); assert(!molFromPkl.has_prop('a')); molFromPkl.delete(); } function test_remove_hs_details() { let mol; let smi; mol = RDKitModule.get_mol('C([H])([H])([H])C([2H])([H])C([H])([H])[H]', JSON.stringify({removeHs: false})); smi = mol.get_smiles(); assert(smi === '[H]C([H])([H])C([H])([2H])C([H])([H])[H]'); assert(mol.remove_hs_in_place(JSON.stringify({removeIsotopes: false}))); smi = mol.get_smiles(); assert(smi === '[2H]C(C)C'); assert(mol.remove_hs_in_place(JSON.stringify({removeIsotopes: true}))); smi = mol.get_smiles(); assert(smi === 'CCC'); mol.delete(); } function test_get_mol_remove_hs() { const mbIn = ` MJ240300 8 8 0 0 0 0 0 0 0 0999 V2000 -1.4955 1.1152 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.2099 0.7027 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.2099 -0.1223 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.4955 -0.5348 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.7810 -0.1223 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.7810 0.7027 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.0666 1.1152 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 -2.9244 -0.5348 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 1 2 2 0 0 0 0 2 3 1 0 0 0 0 3 4 2 0 0 0 0 4 5 1 0 0 0 0 5 6 2 0 0 0 0 6 1 1 0 0 0 0 6 7 1 0 0 0 0 3 8 1 0 0 0 0 M ISO 1 7 2 M END `; const noDetails = {}; const removeHsTrue = { removeHs: true }; const removeHsFalse = { removeHs: false }; const deuteriumCoords = ' -0.0666 1.1152 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0'; const hydrogenCoords = ' -2.9244 -0.5348 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0'; let mol; let mbOut; let smiOut; let jb; let smi; [noDetails, removeHsFalse].forEach((details) => { mol = RDKitModule.get_mol(mbIn, JSON.stringify(details)); assert(mol); mbOut = mol.get_molblock(); assert(mbOut); assert(mbOut.includes(deuteriumCoords)); assert(mbOut.includes(hydrogenCoords)); if (!jb) { jb = mol.get_json(); assert(jb); } if (!smi) { smi = mol.get_smiles(); assert(smi); } mol.delete(); }); mol = RDKitModule.get_mol(mbIn, JSON.stringify(removeHsTrue)); assert(mol); mbOut = mol.get_molblock(); assert(mbOut); assert(mbOut.includes(deuteriumCoords)); assert(!mbOut.includes(hydrogenCoords)); mol.delete(); [noDetails, removeHsFalse].forEach((details) => { mol = RDKitModule.get_mol(mbIn, JSON.stringify(details)); assert(mol); mbOut = mol.get_molblock(); assert(mbOut); assert(mbOut.includes(deuteriumCoords)); assert(mbOut.includes(hydrogenCoords)); mol.delete(); }); mol = RDKitModule.get_mol(jb, JSON.stringify(removeHsTrue)); assert(mol); mbOut = mol.get_molblock(); assert(mbOut); assert(mbOut.includes(deuteriumCoords)); assert(!mbOut.includes(hydrogenCoords)); mol.delete(); [noDetails, removeHsTrue].forEach((details) => { mol = RDKitModule.get_mol(smi, JSON.stringify(details)); assert(mol); smiOut = mol.get_smiles(); assert(smiOut); assert(smiOut.includes('[2H]')); assert(!smiOut.includes('[H]')); mol.delete(); }); mol = RDKitModule.get_mol(smi, JSON.stringify(removeHsFalse)); assert(mol); smiOut = mol.get_smiles(); assert(smiOut); assert(smiOut.includes('[2H]')); assert(smiOut.includes('[H]')); mol.delete(); } function test_png_metadata() { const PNG_COLCHICINE_NO_METADATA = "/../../GraphMol/FileParsers/test_data/colchicine.no_metadata.png"; const PNG_COLCHICINE_WITH_METADATA = "/../../GraphMol/FileParsers/test_data/colchicine.png"; const PNG_PENICILLIN_METADATA = "penicillin_metadata.png"; const PNG_PENICILLIN_AMOXICILLIN_METADATA = "penicillin_amoxicillin_metadata.png"; const PNG_COLCHICINE_AMOXICILLIN_METADATA = "colchicine_amoxicillin_metadata.png"; const BENZYLPENICILLIN_SMI = "CC1([C@@H](N2[C@H](S1)[C@@H](C2=O)NC(=O)Cc3ccccc3)C(=O)O)C"; const BENZYLPENICILLIN_CAN_SMI = "CC1(C)S[C@@H]2[C@H](NC(=O)Cc3ccccc3)C(=O)N2[C@H]1C(=O)O"; const AMOXICILLIN_SMI = "O=C(O)[C@@H]2N3C(=O)[C@@H](NC(=O)[C@@H](c1ccc(O)cc1)N)[C@H]3SC2(C)C"; const AMOXICILLIN_CAN_SMI = "CC1(C)S[C@@H]2[C@H](NC(=O)[C@H](N)c3ccc(O)cc3)C(=O)N2[C@H]1C(=O)O"; let mol; let mols; let molSan; const png_no_metadata_buf = fs.readFileSync(__dirname + PNG_COLCHICINE_NO_METADATA); const png_no_metadata_blob = new Uint8Array(png_no_metadata_buf.length); const png_no_metadata_blob2 = new Uint8Array(png_no_metadata_buf.length); png_no_metadata_buf.copy(png_no_metadata_blob); png_no_metadata_buf.copy(png_no_metadata_blob2); const png_with_metadata_buf = fs.readFileSync(__dirname + PNG_COLCHICINE_WITH_METADATA); const png_with_metadata_blob = new Uint8Array(png_with_metadata_buf.length); png_with_metadata_buf.copy(png_with_metadata_blob); assert(!RDKitModule.get_mol_from_png_blob(png_no_metadata_blob)); assert(!RDKitModule.get_mols_from_png_blob(png_no_metadata_blob)); let penicillin = RDKitModule.get_mol(BENZYLPENICILLIN_SMI); assert(penicillin); assert(penicillin.set_new_coords()); let png_penicillin_metadata_blob = penicillin.add_to_png_blob(png_no_metadata_blob, "{\"includePkl\":false,\"includeSmiles\":true,\"includeMol\":true}"); penicillin.delete(); assert(png_penicillin_metadata_blob); fs.writeFileSync(PNG_PENICILLIN_METADATA, png_penicillin_metadata_blob); penicillin = RDKitModule.get_mol_from_png_blob(png_penicillin_metadata_blob); assert(penicillin); assert.equal(penicillin.has_coords(), 2); penicillin.delete(); RDKitModule.enable_logging() mol = RDKitModule.get_mol_from_png_blob(png_with_metadata_blob); assert(mol); assert.equal(mol.has_coords(), 2); mol.delete(); mols = RDKitModule.get_mols_from_png_blob(png_with_metadata_blob); assert(!mols); mols = RDKitModule.get_mols_from_png_blob(png_with_metadata_blob, JSON.stringify({ includePkl: true, includeSmiles: true })); assert(!mols); mols = RDKitModule.get_mols_from_png_blob( png_with_metadata_blob, JSON.stringify({ includeSmiles: true })); assert(mols); assert.equal(mols.size(), 1); mol = mols.next(); assert.equal(mol.has_coords(), 2); mol.delete(); mols.delete(); assert(!RDKitModule.get_mol_from_png_blob(png_penicillin_metadata_blob, "{\"includePkl\":true,\"includeSmiles\":false,\"includeMol\":false}")); penicillin = RDKitModule.get_mol_from_png_blob(png_penicillin_metadata_blob, "{\"includePkl\":false,\"includeSmiles\":false,\"includeMol\":true,\"sanitize\":false,\"removeHs\":false,\"assignStereo\":false,\"fastFindRings\":false}"); assert(penicillin); assert.equal(penicillin.has_coords(), 2); smi = penicillin.get_smiles(); assert.notEqual(smi, BENZYLPENICILLIN_CAN_SMI); molSan = RDKitModule.get_mol(smi) assert.equal(molSan.get_smiles(), BENZYLPENICILLIN_CAN_SMI); molSan.delete(); penicillin.delete(); assert(!RDKitModule.get_mol_from_png_blob(png_no_metadata_blob2)); penicillin = RDKitModule.get_mol(BENZYLPENICILLIN_SMI); assert(penicillin); let amoxicillin = RDKitModule.get_mol(AMOXICILLIN_SMI); assert(amoxicillin); assert(amoxicillin.set_new_coords()); png_penicillin_metadata_blob = penicillin.add_to_png_blob(png_no_metadata_blob2, "{\"includePkl\":false,\"includeMol\":true,\"CX_ALL_BUT_COORDS\":true}"); assert(png_penicillin_metadata_blob); let png_penicillin_amoxicillin_metadata_blob = amoxicillin.add_to_png_blob(png_penicillin_metadata_blob, "{\"includePkl\":false,\"includeMol\":true,\"CX_ALL_BUT_COORDS\":true}"); assert(png_penicillin_amoxicillin_metadata_blob); fs.writeFileSync(PNG_PENICILLIN_AMOXICILLIN_METADATA, png_penicillin_amoxicillin_metadata_blob); mol = RDKitModule.get_mol_from_png_blob(png_penicillin_amoxicillin_metadata_blob, "{\"sanitize\":false,\"removeHs\":false,\"assignStereo\":false,\"fastFindRings\":false}"); assert(mol); assert(!mol.has_coords()); smi = mol.get_smiles(); assert.equal(smi, BENZYLPENICILLIN_CAN_SMI); mol.delete(); assert(!RDKitModule.get_mol_from_png_blob(png_penicillin_amoxicillin_metadata_blob, "{\"includePkl\":false,\"includeSmiles\":false,\"includeMol\":false}")); mol = RDKitModule.get_mol_from_png_blob(png_penicillin_amoxicillin_metadata_blob, "{\"includePkl\":true,\"includeSmiles\":false,\"includeMol\":true}"); assert(mol); assert.equal(mol.has_coords(), 2); smi = mol.get_smiles(); assert.equal(smi, BENZYLPENICILLIN_CAN_SMI); mol.delete(); mols = RDKitModule.get_mols_from_png_blob(png_penicillin_amoxicillin_metadata_blob); assert(!mols); mols = RDKitModule.get_mols_from_png_blob( png_penicillin_amoxicillin_metadata_blob, JSON.stringify({ includeSmiles: true })); assert(mols); assert.equal(mols.size(), 2); mol = mols.at(0); assert(!mol.has_coords()); smi = mol.get_smiles(); assert.equal(smi, BENZYLPENICILLIN_CAN_SMI); assert(mol.get_morgan_fp()); mol.delete(); mol = mols.at(1); assert(!mol.has_coords()); smi = mol.get_smiles(); assert.equal(smi, AMOXICILLIN_CAN_SMI); assert(mol.get_morgan_fp()); mol.delete(); mols.delete(); mols = RDKitModule.get_mols_from_png_blob(png_penicillin_amoxicillin_metadata_blob, JSON.stringify({ includePkl: false, includeMol: true, sanitize: false, removeHs: false, assignStereo: false, fastFindRings: false })); assert(mols); assert.equal(mols.size(), 2); mol = mols.at(0); assert(mol.has_coords()); smi = mol.get_smiles(); assert.notEqual(smi, BENZYLPENICILLIN_CAN_SMI); molSan = RDKitModule.get_mol(smi) assert.equal(molSan.get_smiles(), BENZYLPENICILLIN_CAN_SMI); molSan.delete(); mol.delete(); mol = mols.at(1); assert(mol.has_coords()); smi = mol.get_smiles(); assert.notEqual(smi, AMOXICILLIN_CAN_SMI); molSan = RDKitModule.get_mol(smi) assert.equal(molSan.get_smiles(), AMOXICILLIN_CAN_SMI); molSan.delete(); mol.delete(); mols.delete(); let png_colchicine_amoxicillin_metadata_blob = amoxicillin.add_to_png_blob( png_with_metadata_blob, JSON.stringify({ includeMol: true, CX_ALL_BUT_COORDS:true })); assert(png_colchicine_amoxicillin_metadata_blob); fs.writeFileSync(PNG_COLCHICINE_AMOXICILLIN_METADATA, png_colchicine_amoxicillin_metadata_blob); mols = RDKitModule.get_mols_from_png_blob(png_colchicine_amoxicillin_metadata_blob, "{\"includePkl\":false,\"includeMol\":true}"); assert.equal(mols.size(), 1); mol = mols.at(0); assert.equal(mol.has_coords(), 2); mol.delete(); mols.delete(); mols = RDKitModule.get_mols_from_png_blob(png_colchicine_amoxicillin_metadata_blob, "{\"includeSmiles\":true}"); assert.equal(mols.size(), 2); assert.equal(mols.at(0).has_coords(), 2); assert(!mols.at(1).has_coords()); mols.delete(); penicillin.delete(); amoxicillin.delete(); const colchicine = RDKitModule.get_mol('COc1cc2c(c(OC)c1OC)-c1ccc(OC)c(=O)cc1[C@@H](NC(C)=O)CC2'); assert(colchicine); png_no_metadata_buf.copy(png_no_metadata_blob); let png_colchicine_metadata_blob; png_colchicine_metadata_blob = colchicine.add_to_png_blob(png_no_metadata_blob); mol = RDKitModule.get_mol_from_png_blob(png_colchicine_metadata_blob); assert(mol); assert.equal(mol.get_num_atoms(), 29); assert(!mol.has_coords()); mol.delete(); // use SMILES png_colchicine_metadata_blob = colchicine.add_to_png_blob(png_no_metadata_blob, JSON.stringify({ includePkl: false })); mol = RDKitModule.get_mol_from_png_blob(png_colchicine_metadata_blob); assert(mol); assert.equal(mol.get_num_atoms(), 29); assert(!mol.has_coords()); mol.delete(); // use MOL png_colchicine_metadata_blob = colchicine.add_to_png_blob(png_no_metadata_blob, JSON.stringify({ includePkl: false, includeSmiles: false, includeMol: true })); mol = RDKitModule.get_mol_from_png_blob(png_colchicine_metadata_blob); assert(mol); assert.equal(mol.get_num_atoms(), 29); assert.equal(mol.has_coords(), 2); mol.delete(); // use PKL colchicine.set_new_coords(); assert.equal(colchicine.has_coords(), 2); const PROPERTY_NAME = 'property'; const PROPERTY_VALUE = 'value'; colchicine.set_prop(PROPERTY_NAME, PROPERTY_VALUE); png_colchicine_metadata_blob = colchicine.add_to_png_blob(png_no_metadata_blob, JSON.stringify({ includePkl: true, includeSmiles: false, includeMol: false, propertyFlags: { NoProps: true } })); mol = RDKitModule.get_mol_from_png_blob(png_colchicine_metadata_blob); assert(mol); assert.equal(mol.get_num_atoms(), 29); assert.equal(mol.has_coords(), 2); assert(!mol.has_prop(PROPERTY_NAME)); mol.delete(); png_colchicine_metadata_blob = colchicine.add_to_png_blob(png_no_metadata_blob, JSON.stringify({ includePkl: true, includeSmiles: false, includeMol: false, propertyFlags: { AllProps: true } })); mol = RDKitModule.get_mol_from_png_blob(png_colchicine_metadata_blob); assert(mol); assert.equal(mol.get_num_atoms(), 29); assert.equal(mol.has_coords(), 2); assert(mol.has_prop(PROPERTY_NAME)); assert(mol.get_prop(PROPERTY_NAME) == PROPERTY_VALUE); mol.delete(); png_colchicine_metadata_blob = colchicine.add_to_png_blob(png_no_metadata_blob, JSON.stringify({ includePkl: false, includeSmiles: true, includeMol: false, propertyFlags: { NoProps: true }, CX_ALL_BUT_COORDS: true })); mol = RDKitModule.get_mol_from_png_blob(png_colchicine_metadata_blob); assert(mol); assert.equal(mol.get_num_atoms(), 29); assert(!mol.has_coords()); assert(!mol.has_prop(PROPERTY_NAME)); mol.delete(); // use original wedging const colchicineUnusualWedging = RDKitModule.get_mol(` RDKit 2D 29 31 0 0 0 0 0 0 0 0999 V2000 6.4602 1.0300 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 5.3062 1.9883 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 3.8993 1.4680 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.7453 2.4262 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1.3384 1.9059 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1.0856 0.4273 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.2396 -0.5309 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1.9868 -2.0094 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 3.1408 -2.9677 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 3.6465 -0.0106 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 4.8005 -0.9688 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 4.5477 -2.4474 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.2280 -0.2968 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.1857 -1.7387 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.6836 -2.9611 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.1813 -3.0436 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.7569 -4.4288 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 -4.2442 -4.6230 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -3.1797 -1.9240 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -4.6215 -2.3378 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 -2.9268 -0.4455 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.6132 0.2787 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -2.0269 1.7205 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -3.5055 1.9733 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 -4.0258 3.3802 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -5.5043 3.6330 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -3.0675 4.5342 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 -1.1576 2.9429 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.3401 3.0254 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 0 2 3 1 0 3 4 2 0 4 5 1 0 5 6 2 0 6 7 1 0 7 8 1 0 8 9 1 0 7 10 2 0 10 11 1 0 11 12 1 0 6 13 1 0 13 14 2 0 14 15 1 0 15 16 2 0 16 17 1 0 17 18 1 0 16 19 1 0 19 20 2 0 19 21 1 0 21 22 2 0 23 22 1 1 23 24 1 0 24 25 1 0 25 26 1 0 25 27 2 0 23 28 1 0 28 29 1 0 10 3 1 0 22 13 1 0 29 5 1 0 M END `); assert(colchicineUnusualWedging); assert.equal(colchicineUnusualWedging.has_coords(), 2); assert(colchicineUnusualWedging.get_cxsmiles().includes('wU:22.24|')); assert(colchicineUnusualWedging.get_cxsmiles(JSON.stringify({ CX_ALL: true, restoreBondDirOption: 'RestoreBondDirOptionTrue' })).includes('wU:22.23|')); png_colchicine_metadata_blob = colchicineUnusualWedging.add_to_png_blob(png_no_metadata_blob, JSON.stringify({ includePkl: true, includeSmiles: true, includeMol: true, propertyFlags: { AtomProps: true, BondProps: true } })); mol = RDKitModule.get_mol_from_png_blob(png_colchicine_metadata_blob); // the mol is restored from pickle, so it will retain // original molblock wedging assert(mol); assert.equal(mol.get_num_atoms(), 29); assert.equal(mol.has_coords(), 2); assert(mol.get_cxsmiles(JSON.stringify({ CX_ALL: true, restoreBondDirOption: 'RestoreBondDirOptionTrue' })).includes('wU:22.23|')); assert(mol.get_cxsmiles(JSON.stringify({ CX_ALL: true, restoreBondDirOption: 'RestoreBondDirOptionClear' })).includes('wU:22.24|')); assert(mol.get_molblock().includes(' 23 24 1 1')); assert(mol.get_molblock(JSON.stringify({ useMolBlockWedging: true })).includes(' 23 22 1 1')); mol.delete(); // the mol is restored from CXSMILES, so it will not retain // original molblock wedging, as it was not stored in the CXSMILES string png_colchicine_metadata_blob = colchicineUnusualWedging.add_to_png_blob(png_no_metadata_blob, JSON.stringify({ includePkl: false, includeSmiles: true, includeMol: true, propertyFlags: { AtomProps: true, BondProps: true } })); mol = RDKitModule.get_mol_from_png_blob(png_colchicine_metadata_blob); assert(mol); assert.equal(mol.get_num_atoms(), 29); assert.equal(mol.has_coords(), 2); assert(mol.get_cxsmiles(JSON.stringify({ CX_ALL: true, restoreBondDirOption: 'RestoreBondDirOptionTrue' })).includes('wU:22.24|')); assert(mol.get_cxsmiles(JSON.stringify({ CX_ALL: true, restoreBondDirOption: 'RestoreBondDirOptionClear' })).includes('wU:22.24|')); assert(mol.get_molblock().includes(' 23 24 1 1')); assert(mol.get_molblock(JSON.stringify({ useMolBlockWedging: true })).includes(' 23 24 1 1')); mol.delete(); // the mol is restored from CXSMILES, but restoreBondDirOption was set // to 'RestoreBondDirOptionTrue', so it will not retain // original molblock wedging, as it was stored in the CXSMILES string png_colchicine_metadata_blob = colchicineUnusualWedging.add_to_png_blob(png_no_metadata_blob, JSON.stringify({ includePkl: false, includeSmiles: true, includeMol: true, propertyFlags: { AtomProps: true, BondProps: true }, restoreBondDirOption: 'RestoreBondDirOptionTrue' })); mol = RDKitModule.get_mol_from_png_blob(png_colchicine_metadata_blob); assert(mol); assert.equal(mol.get_num_atoms(), 29); assert.equal(mol.has_coords(), 2); assert(mol.get_cxsmiles(JSON.stringify({ CX_ALL: true, restoreBondDirOption: 'RestoreBondDirOptionTrue' })).includes('wU:22.23|')); assert(mol.get_cxsmiles(JSON.stringify({ CX_ALL: true, restoreBondDirOption: 'RestoreBondDirOptionClear' })).includes('wU:22.24|')); assert(mol.get_molblock().includes(' 23 22 1 1')); assert(mol.get_molblock(JSON.stringify({ useMolBlockWedging: true })).includes(' 23 22 1 1')); mol.delete(); colchicineUnusualWedging.delete(); } function test_combine_with() { { var mol = RDKitModule.get_mol("CC"); assert(mol); var other = RDKitModule.get_mol("NCC"); assert(other); assert(!mol.combine_with(other)); assert.equal(mol.get_num_atoms(), 5); assert(mol.get_smiles() === "CC.CCN"); mol.delete(); other.delete(); } { var mol = RDKitModule.get_mol("C1CC1 |(0.866025,0,;-0.433013,0.75,;-0.433013,-0.75,)|"); var mol_copy = RDKitModule.get_mol_copy(mol); assert(mol); var other = RDKitModule.get_mol("C1CNC1 |(-1.06066,0,;0,-1.06066,;1.06066,0,;0,1.06066,)|"); assert(other); assert(!mol.combine_with(other, JSON.stringify({offset: [4.0, 0.0, 0.0]}))); assert.equal(mol.get_num_atoms(), 7); assert(mol.get_smiles() === "C1CC1.C1CNC1"); assert(mol.get_molblock().includes(" 4.0000")); mol.delete(); assert(!mol_copy.combine_with(other, JSON.stringify({offset: [9.0, 0.0, 0.0]}))); assert.equal(mol_copy.get_num_atoms(), 7); assert(mol_copy.get_smiles() === "C1CC1.C1CNC1"); assert(mol_copy.get_molblock().includes(" 9.0000")); mol_copy.delete(); other.delete(); } } function test_get_coords() { { var mol = RDKitModule.get_mol("C1CC1 |(0.866025,0,;-0.433013,0.75,;-0.433013,-0.75,)|"); assert(mol); assert.equal(mol.has_coords(), 2); var pos = mol.get_coords(); assert(Array.isArray(pos)); assert(pos.length === mol.get_num_atoms()); assert(pos.every((xyz) => Array.isArray(xyz) && xyz.length === 3 && xyz.every((c) => typeof c === "number"))); assert(JSON.stringify(pos) === "[[0.866025,0,0],[-0.433013,0.75,0],[-0.433013,-0.75,0]]"); mol.delete(); } { var mol = RDKitModule.get_mol("C1CC1"); assert(mol); assert(!mol.has_coords()); var pos = mol.get_coords(); assert(Array.isArray(pos)); assert(!pos.length); mol.delete(); } } function test_get_v3K_v2K_molblock() { var mol = RDKitModule.get_mol('c1cc(O)ccc1'); assert(mol); var molblock = mol.get_v3Kmolblock(); var mol2 = RDKitModule.get_mol(molblock); assert(mol2); var smiles = mol2.get_smiles(); assert(smiles === 'Oc1ccccc1'); mol2.delete(); molblock = mol.get_v3Kmolblock(JSON.stringify({ kekulize: false })); assert(molblock.includes('M V30 1 4 1 2')); molblock = mol.get_molblock(JSON.stringify({ forceMDLVersion: 'V3000' })); assert(molblock.includes('V3000')); molblock = mol.get_v3Kmolblock(JSON.stringify({ forceMDLVersion: 'V2000' })); assert(molblock.includes('V3000')); mol.delete(); var mol3 = RDKitModule.get_mol('N->[Pt+2](Cl)(Cl)<-N'); assert(mol3); molblock = mol3.get_molblock(); assert(molblock.includes('V3000')); assert(molblock.includes('M V30 4 9 5 2')); molblock = mol3.get_molblock(JSON.stringify({forceMDLVersion: 'V2000'})); assert(molblock.includes('V2000')); assert(molblock.includes(' 5 2 9 0')); molblock = mol3.get_v3Kmolblock(JSON.stringify({forceMDLVersion: 'V2000'})); assert(molblock.includes('V3000')); assert(molblock.includes('M V30 4 9 5 2')); molblock = mol3.get_v2Kmolblock(JSON.stringify({forceMDLVersion: 'V3000'})); assert(molblock.includes('V2000')); assert(molblock.includes(' 5 2 9 0')); mol3.delete(); } function test_return_draw_coords() { var mb = ` RDKit 2D 3 3 0 0 0 0 0 0 0 0999 V2000 0.0000 0.8930 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.7734 -0.4465 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.7734 -0.4465 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 0 2 3 1 0 1 3 1 0 M END`; var reference; var highlight; var aboveTol; var mol = RDKitModule.get_mol(mb); assert(mol); res = mol.get_svg_with_highlights(JSON.stringify({ width: 300, height: 200, padding: 0.2, returnDrawCoords: true })); assert(res); res = JSON.parse(res); assert(res.drawCoords); assert(res.svg); reference = res.drawCoords.flat(); res = mol.get_svg_with_highlights(JSON.stringify({ width: 300, height: 200, padding: 0.2, atoms: [0], returnDrawCoords: true })); assert(res); res = JSON.parse(res); assert(res.drawCoords); assert(res.svg); highlight = res.drawCoords.flat(); aboveTol = reference.some((ref, i) => (Math.abs(ref - highlight[i]) > 0.1)); assert(aboveTol); res = mol.get_svg_with_highlights(JSON.stringify({ width: 300, height: 200, padding: 0.2, atoms: [0], returnDrawCoords: true, drawingExtentsInclude: { ALL: true, HIGHLIGHTS: false } })); assert(res); res = JSON.parse(res); assert(res.drawCoords); assert(res.svg); highlight = res.drawCoords.flat(); aboveTol = reference.some((ref, i) => (Math.abs(ref - highlight[i]) > 0.1)); assert(!aboveTol); mol.delete(); } function test_get_substruct_match_params() { var mol = RDKitModule.get_mol('Br[C@H](F)CCC[C@@H](Br)F'); var query1 = RDKitModule.get_mol('Br[#6@H](C)F'); var query2 = RDKitModule.get_mol('Br[#6@@H](C)F'); assert(mol && query1 && query2); var res1; var res2; res1 = JSON.parse(mol.get_substruct_matches(query1)); res2 = JSON.parse(mol.get_substruct_matches(query2)); assert (res1.length === 2); assert (res2.length === 2); res1.sort((a, b) => a.atoms - b.atoms); res2.sort((a, b) => a.atoms - b.atoms); assert.equal(JSON.stringify(res1), JSON.stringify(res2)); res1 = JSON.parse(mol.get_substruct_match(query1)); res2 = JSON.parse(mol.get_substruct_match(query2)); assert (!Array.isArray(res1) && !Array.isArray(res2)); assert.equal(JSON.stringify(res1), JSON.stringify(res2)); res1 = JSON.parse(mol.get_substruct_matches(query1, JSON.stringify({ useChirality: true }))); res2 = JSON.parse(mol.get_substruct_matches(query2, JSON.stringify({ useChirality: true }))); assert (res1.length === 1); assert (res2.length === 1); assert.notEqual(JSON.stringify(res1), JSON.stringify(res2)); res1 = JSON.parse(mol.get_substruct_match(query1, JSON.stringify({ useChirality: true }))); res2 = JSON.parse(mol.get_substruct_match(query2, JSON.stringify({ useChirality: true }))); assert (!Array.isArray(res1) && !Array.isArray(res2)); assert.notEqual(JSON.stringify(res1), JSON.stringify(res2)); } initRDKitModule().then(function(instance) { var done = {}; const waitAllTestsFinished = () => { const poll = resolve => { if (Object.values(done).every(v => v)) { resolve(); } else { setTimeout(() => poll(resolve), 100); } } return new Promise(poll); } RDKitModule = instance; console.log(RDKitModule.version()); test_basics(); test_molblock_nostrict(); test_molblock_rgp(); test_get_aromatic_kekule_form(); test_sketcher_services(); test_sketcher_services2(); test_abbreviations(); if (RDKitModule.SubstructLibrary) { test_substruct_library(done); test_substruct_library_merge_hs(); test_substruct_library_empty_mols(); test_substruct_library_empty_lib(); test_substruct_library_empty_query(); } test_generate_aligned_coords(); test_isotope_labels(); test_generate_aligned_coords_allow_rgroups(); test_generate_aligned_coords_accept_failure(); test_generate_aligned_coords_align_only(); test_get_mol_no_kekulize(); test_get_smarts(); test_get_cxsmarts(); test_has_coords(); test_kekulize(); test_sanitize(); test_removehs(); test_normalize_depiction(); test_straighten_depiction(); test_flexicanvas(); if (RDKitModule.get_rxn) { test_rxn_drawing(); test_run_reaction(); } test_legacy_stereochem(); test_allow_non_tetrahedral_chirality(); test_prop(); test_highlights(); test_add_chiral_hs(); test_wedging_all_within_scaffold(); test_wedging_outside_scaffold(); test_wedging_if_no_match(); test_get_frags(); if (RDKitModule.Mol.prototype.get_mmpa_frags) { test_get_mmpa_frags(); } test_hs_in_place(); test_query_colour(); test_alignment_r_groups_aromatic_ring(); test_is_valid_deprecated(); test_mol_list(); test_get_num_atoms_bonds(); if (RDKitModule.get_mcs_as_mol) { test_mcs(); } test_sanitize_no_kekulize_no_setaromaticity(); test_partial_sanitization(); test_capture_logs(); test_rgroup_match_heavy_hydro_none_charged(); test_get_sss_json(); test_relabel_mapped_dummies(); test_assign_cip_labels(); test_smiles_smarts_params(); test_wedged_bond_atropisomer(); test_get_molblock_use_molblock_wedging(); test_assign_chiral_tags_from_mol_parity(); test_make_dummies_queries(); test_get_mol_copy(); test_multi_highlights(); if (RDKitModule.RGroupDecomposition) { test_singlecore_rgd(); test_multicore_rgd(); } test_bw_palette(); test_custom_palette(); if (RDKitModule.molzip) { test_molzip(); } test_pickle(); test_remove_hs_details(); test_get_mol_remove_hs(); test_png_metadata(); test_combine_with(); test_get_coords(); test_get_v3K_v2K_molblock(); test_return_draw_coords(); test_get_substruct_match_params(); waitAllTestsFinished().then(() => console.log("Tests finished successfully") ); });