Files
enviPy-bayer/static/js/ketcher2/test/utils/molcompare.js
2025-06-23 20:13:54 +02:00

139 lines
4.2 KiB
JavaScript

/****************************************************************************
* Copyright 2017 EPAM Systems
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
'use strict';
const defaultCmpOptions = {
stripSpaces: false,
skipCompare: [],
eps: 0.00011
};
const numberPattern = /-?\d+[\.,]?\d*/g;
function epsEqu(x, y, eps) {
eps = eps || Number.EPSILON * Math.max(Math.abs(x), Math.abs(y));
return Math.abs(x - y) <= eps;
}
function arraysEquals(sArray, rArray, eqFunc) {
return sArray === rArray ||
(
sArray.length === rArray.length &&
sArray.every((elem, index) => eqFunc ? eqFunc(elem, rArray[index]) : elem === rArray[index])
);
}
function extractNumbers(source) {
const matches = source.match(numberPattern);
return {
numbers: matches ? matches.map(parseFloat) : [],
characters: source.replace(numberPattern, '').split(/\s+/)
};
}
function compareFile(source, dest, options) {
const sourceStr = source.split(/\r?\n+/);
const destStr = dest.split(/\r?\n+/);
for (var i = 0; i < sourceStr.length; i++) {
if (options.stripSpaces) {
sourceStr[i] = sourceStr[i].trim();
destStr[i] = destStr[i].trim();
}
const sDataSplitted = extractNumbers(sourceStr[i]);
const rDataSplitted = extractNumbers(destStr[i]);
const numberEquals = arraysEquals(sDataSplitted.numbers, rDataSplitted.numbers, (x, y) => epsEqu(x, y, options.eps));
const characterEquals = arraysEquals(sDataSplitted.characters, rDataSplitted.characters);
if (!numberEquals || !characterEquals)
throw new Error(`\nsource: '${sourceStr[i]}'\ndest: '${destStr[i]}'`);
}
return true;
}
function compareRaw(source, dest, options) {
const sDataMols = source.split('M END');
const rDataMols = dest.split('M END');
let newSdata, newRdata;
if (sDataMols.length !== rDataMols.length)
throw new Error(`\nCount of content blocks are not equal: source = ${sDataMols.length}, dest = ${rDataMols.length}`);
options = Object.assign({}, defaultCmpOptions, options);
for (let i = 0; i < sDataMols.length - 1; i++) {
const sV2000DataIndex = sDataMols[i].indexOf('V2000\n');
const sV3000DataIndex = sDataMols[i].indexOf('V3000\n');
const rV2000DataIndex = rDataMols[i].indexOf('V2000\n');
const rV3000DataIndex = rDataMols[i].indexOf('V3000\n');
newSdata = sDataMols[i].substring(6 + (sV3000DataIndex === -1 ? sV2000DataIndex : sV3000DataIndex));
newRdata = rDataMols[i].substring(6 + (rV3000DataIndex === -1 ? rV2000DataIndex : rV3000DataIndex));
if (!compareFile(newSdata, newRdata, options))
return false;
}
return true;
}
function compareObjects(source, dest, options, parentKey) {
if (typeof source !== typeof dest)
throw new Error(`\ntypes not equal: type ${typeof source} of ${source} vs type ${typeof dest} of ${dest} in ${parentKey}`);
if (typeof source !== 'object')
return source === dest;
return Object.keys(source)
.filter(prop => !options.skipCompare.includes(prop))
.every(key => {
if (dest[key] === undefined)
throw new Error(`\nDest object has no key ${key}`);
if (!compareObjects(source[key], dest[key], options, key))
throw new Error(`\nsource: '${source[key]}'\ndest: '${dest[key]}' in ${key}`);
return true;
});
}
function unicodeLiteral(str) {
function fixedHex(number, length) {
let str = number.toString(16).toUpperCase();
while (str.length < length)
str = "0" + str;
return str;
}
let result = "";
for (var i = 0; i < str.length; ++i) {
if (str.charCodeAt(i) > 126 || str.charCodeAt(i) < 32)
result += "\\u" + fixedHex(str.charCodeAt(i), 4);
else
result += str[i];
}
return result;
}
module.exports = {
raw: compareRaw,
objects: compareObjects,
unicodeLiteral: unicodeLiteral
};