Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Molecule } from 'openchemlib';
import { expect, test } from 'vitest';
import { expect, onTestFinished, test, vi } from 'vitest';

import { TopicMolecule } from '../TopicMolecule';

Expand Down Expand Up @@ -204,30 +204,35 @@ test('canonizedProchiralities is transferred across TopicMolecule instances with
// (e.g. after expanding hydrogens) should not recompute CIP.
const molecule = Molecule.fromSmiles('CC(Cl)CC');
const original = new TopicMolecule(molecule);
const labels = original.prochiralities;
const labelledCount = labels.filter((l) => l !== undefined).length;

expect(labelledCount).toBe(2);
// Compute the original labels once, populating its prochirality cache.
expect(
original.prochiralities.filter((l) => l !== undefined).toSorted(),
).toStrictEqual(['r', 's']);

const oclModule = molecule.getOCL().Molecule;
let cipCalls = 0;
const originalEnsure = oclModule.prototype.ensureHelperArrays;
oclModule.prototype.ensureHelperArrays = function spy(bits) {
if (bits === oclModule.cHelperCIP) cipCalls++;
return originalEnsure.call(this, bits);
};
// Count only the dedicated CIP computation (the exact cHelperCIP bit);
// composite requests that merely include that bit are unrelated.
const oclMolecule = molecule.getOCL().Molecule;
const spy = vi.spyOn(oclMolecule.prototype, 'ensureHelperArrays');
onTestFinished(() => spy.mockRestore());

try {
const reused = original.fromMolecule(molecule);
const reusedLabels = reused.prochiralities;
const reused = original.fromMolecule(molecule);

expect(
reusedLabels.filter((l) => l !== undefined).toSorted(),
).toStrictEqual(['r', 's']);
expect(cipCalls).toBe(0);
} finally {
oclModule.prototype.ensureHelperArrays = originalEnsure;
}
// The transferred entry is the very same object: that shared reference is the
// whole optimisation — there is nothing to recompute.
expect(reused.cache.prochiralityByEnantioID).toBe(
original.cache.prochiralityByEnantioID,
);

expect(
reused.prochiralities.filter((l) => l !== undefined).toSorted(),
).toStrictEqual(['r', 's']);

const cipCalls = spy.mock.calls.filter(
([bits]) => bits === oclMolecule.cHelperCIP,
).length;

expect(cipCalls).toBe(0);
});

test('CC(Cl)CC: implicit-H molecule gets no labels, only moleculeWithH does', () => {
Expand Down
26 changes: 9 additions & 17 deletions src/topic/__tests__/getCanonizedDiaIDs.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Molecule } from 'openchemlib';
import { expect, test } from 'vitest';
import { expect, onTestFinished, test, vi } from 'vitest';

import { TopicMolecule } from '../TopicMolecule';

Expand All @@ -10,22 +10,14 @@ test('symmetric atoms with the same heterotopic rank share a cached diaID (no re
const topicMolecule = new TopicMolecule(molecule);

const oclModule = molecule.getOCL().Molecule;
let canonizationCalls = 0;
const originalGetCanonizedIDCode = oclModule.prototype.getCanonizedIDCode;
oclModule.prototype.getCanonizedIDCode = function spy(...args) {
canonizationCalls++;
return originalGetCanonizedIDCode.apply(this, args);
};

try {
const diaIDs = topicMolecule.diaIDs;

expect(diaIDs).toHaveLength(12);
expect(canonizationCalls).toBe(2);
expect(new Set(diaIDs).size).toBe(2);
} finally {
oclModule.prototype.getCanonizedIDCode = originalGetCanonizedIDCode;
}
const spy = vi.spyOn(oclModule.prototype, 'getCanonizedIDCode');
onTestFinished(() => spy.mockRestore());

const diaIDs = topicMolecule.diaIDs;

expect(diaIDs).toHaveLength(12);
expect(spy).toHaveBeenCalledTimes(2);
expect(new Set(diaIDs).size).toBe(2);
});

test('a molecule with all-distinct atoms still gets one canonization per atom', () => {
Expand Down
Loading