Skip to content

Commit 82f858d

Browse files
author
linzhijun
committed
fix
1 parent e416c42 commit 82f858d

11 files changed

Lines changed: 1946 additions & 7 deletions

‎JavaScript/src/AlgorithmEngineHelper.js‎

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,29 @@ export class AlgorithmEngineHelper {
7878
static UnitConversion(src, oldSrcUnit, oldTarUnit, name = null) {
7979
// 与 C# 一致:空字符串或纯空白单位直接返回原值
8080
if (!oldSrcUnit || !oldTarUnit || !oldSrcUnit.trim() || !oldTarUnit.trim()) { return src; }
81+
if (oldSrcUnit === oldTarUnit) { return src; }
8182
if (!this.unitRegex) {
8283
this.unitRegex = /[\s \(\)()\[\]<>]/g;
8384
}
85+
86+
// 与 C# 一致:先尝试原始单位名(如 "short ton" 含空格也能匹配),失败后再去除空格重试
87+
let result = this.tryUnitConvert(src, oldSrcUnit, oldTarUnit);
88+
if (result != null) { return result; }
89+
8490
oldSrcUnit = oldSrcUnit.replace(this.unitRegex, "");
85-
if (oldSrcUnit === oldTarUnit) { return src; }
91+
result = this.tryUnitConvert(src, oldSrcUnit, oldTarUnit);
92+
if (result != null) { return result; }
93+
94+
if (!name) {
95+
throw new Error(`The input item has different units and cannot be converted from [${oldSrcUnit}] to [${oldTarUnit}]`);
96+
}
97+
throw new Error(`The input item [${name}] has different units and cannot be converted from [${oldSrcUnit}] to [${oldTarUnit}]`);
98+
}
8699

100+
/**
101+
* 尝试在四种单位体系中转换,失败返回 null
102+
*/
103+
static tryUnitConvert(src, oldSrcUnit, oldTarUnit) {
87104
if (DistanceConverter.exists(oldSrcUnit, oldTarUnit)) {
88105
let c = new DistanceConverter(oldSrcUnit, oldTarUnit);
89106
return c.leftToRight(src);
@@ -100,10 +117,7 @@ export class AlgorithmEngineHelper {
100117
let c = new VolumeConverter(oldSrcUnit, oldTarUnit);
101118
return c.leftToRight(src);
102119
}
103-
if (!name) {
104-
throw new Error(`The input item has different units and cannot be converted from [${oldSrcUnit}] to [${oldTarUnit}]`);
105-
}
106-
throw new Error(`The input item [${name}] has different units and cannot be converted from [${oldSrcUnit}] to [${oldTarUnit}]`);
120+
return null;
107121
}
108122

109123
/**

‎JavaScript/src/Internals/Visitors/MathFunctionVisitor.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,8 +304,8 @@ const funcDict = {
304304
"ISODD": (args) => new Function_ISODD(args),
305305
"ISNULL": (args) => new Function_ISNULL(args),
306306
"ISNULLORERROR": (args) => new Function_ISNULLORERROR(args),
307-
"AND": (args) => new Function_AND(args),
308-
"OR": (args) => new Function_OR(args),
307+
"AND": (args) => new Function_AND_N(args),
308+
"OR": (args) => new Function_OR_N(args),
309309
"XOR": (args) => new Function_XOR(args),
310310
"NOT": (args) => new Function_NOT(args),
311311
"DEC2BIN": (args) => new Function_DEC2BIN(args),
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import assert from 'assert';
2+
import { AlgorithmEngine } from '../src/AlgorithmEngine.js';
3+
4+
// 对齐 C# FunctionCacheTest
5+
// JS 中对应的能力为 AlgorithmEngine.UseParseCache + Parse/ParseWithoutError
6+
class EngineWithCache extends AlgorithmEngine {
7+
constructor() {
8+
super();
9+
this.UseParseCache = true;
10+
}
11+
}
12+
13+
function testParseWithCacheSameFormulaReturnsSameInstance() {
14+
console.log('开始测试 ParseWithCache_SameFormula_ReturnsSameInstance...');
15+
16+
const cache = new EngineWithCache();
17+
const r1 = cache.Parse("abs(1)");
18+
const r2 = cache.Parse("abs(1)");
19+
assert.ok(r1 != null, "Parse('abs(1)') 不应为空");
20+
assert.strictEqual(r1, r2, "同一公式解析结果应为同一实例");
21+
22+
console.log('ParseWithCache_SameFormula_ReturnsSameInstance 测试通过!');
23+
}
24+
25+
function testParseWithCacheDifferentFormulasReturnsDifferentInstances() {
26+
console.log('开始测试 ParseWithCache_DifferentFormulas_ReturnsDifferentInstances...');
27+
28+
const cache = new EngineWithCache();
29+
const r1 = cache.Parse("abs(1)");
30+
const r2 = cache.Parse("abs(2)");
31+
assert.ok(r1 != null && r2 != null, "解析结果不应为空");
32+
assert.notStrictEqual(r1, r2, "不同公式解析结果应为不同实例");
33+
34+
console.log('ParseWithCache_DifferentFormulas_ReturnsDifferentInstances 测试通过!');
35+
}
36+
37+
function testParseWithCacheStringLeafReturnsFunctionBase() {
38+
console.log('开始测试 ParseWithCache_StringLeaf_ReturnsFunctionBase...');
39+
40+
const cache = new EngineWithCache();
41+
// 修复: String 叶子节点也写入缓存(修复前直接返回不缓存)
42+
const r1 = cache.Parse("'abc'");
43+
const r2 = cache.Parse("'abc'");
44+
assert.ok(r1 != null, "Parse(\"'abc'\") 不应为空");
45+
assert.strictEqual(r1, r2, "字符串叶子节点同一公式解析结果应为同一实例");
46+
47+
console.log('ParseWithCache_StringLeaf_ReturnsFunctionBase 测试通过!');
48+
}
49+
50+
function testParseWithCacheNestedFunctionReturnsFunctionBase() {
51+
console.log('开始测试 ParseWithCache_NestedFunction_ReturnsFunctionBase...');
52+
53+
const cache = new EngineWithCache();
54+
const r = cache.Parse("max(1,2,3)");
55+
assert.ok(r != null, "Parse('max(1,2,3)') 不应为空");
56+
57+
console.log('ParseWithCache_NestedFunction_ReturnsFunctionBase 测试通过!');
58+
}
59+
60+
function testParseWithCacheDiyExpressionReturnsFunctionBase() {
61+
console.log('开始测试 ParseWithCache_DiyExpression_ReturnsFunctionBase...');
62+
63+
const cache = new EngineWithCache();
64+
const r = cache.Parse("myVar");
65+
assert.ok(r != null, "Parse('myVar') 不应为空");
66+
67+
console.log('ParseWithCache_DiyExpression_ReturnsFunctionBase 测试通过!');
68+
}
69+
70+
function testParseWithoutErrorWithCacheCachesResult() {
71+
console.log('开始测试 ParseWithoutError_WithCache...');
72+
73+
const cache = new EngineWithCache();
74+
const r1 = cache.ParseWithoutError("1=1");
75+
const r2 = cache.ParseWithoutError("1=1");
76+
assert.ok(r1 != null, "ParseWithoutError('1=1') 不应为空");
77+
assert.strictEqual(r1, r2, "同一公式 ParseWithoutError 结果应为同一实例");
78+
79+
console.log('ParseWithoutError_WithCache 测试通过!');
80+
}
81+
82+
function testParseCacheInvalidFormulaReturnsNull() {
83+
console.log('开始测试 ParseCache_InvalidFormula_ReturnsNull...');
84+
85+
const cache = new EngineWithCache();
86+
const r = cache.ParseWithoutError("1+");
87+
assert.ok(r == null, "ParseWithoutError('1+') 应为 null");
88+
assert.ok(cache.LastError != null, "无效公式应设置 LastError");
89+
90+
console.log('ParseCache_InvalidFormula_ReturnsNull 测试通过!');
91+
}
92+
93+
function testParseCacheCanEvaluate() {
94+
console.log('开始测试 ParseCache_CanEvaluate...');
95+
96+
const cache = new EngineWithCache();
97+
const r = cache.Parse("abs(1)");
98+
assert.ok(r != null, "Parse('abs(1)') 不应为空");
99+
100+
// 缓存实例仍可正常求值
101+
const e = new EngineWithCache();
102+
const t = e.TryEvaluate_Int("abs(-5)", 0);
103+
assert.strictEqual(t, 5, "abs(-5) 应该等于 5");
104+
105+
console.log('ParseCache_CanEvaluate 测试通过!');
106+
}
107+
108+
// 运行所有测试
109+
function runAllTests() {
110+
try {
111+
testParseWithCacheSameFormulaReturnsSameInstance();
112+
testParseWithCacheDifferentFormulasReturnsDifferentInstances();
113+
testParseWithCacheStringLeafReturnsFunctionBase();
114+
testParseWithCacheNestedFunctionReturnsFunctionBase();
115+
testParseWithCacheDiyExpressionReturnsFunctionBase();
116+
testParseWithoutErrorWithCacheCachesResult();
117+
testParseCacheInvalidFormulaReturnsNull();
118+
testParseCacheCanEvaluate();
119+
console.log('所有测试通过!');
120+
} catch (error) {
121+
console.error('测试失败:', error.message);
122+
process.exit(1);
123+
}
124+
}
125+
126+
// 执行测试
127+
runAllTests();
128+
129+
export {
130+
testParseWithCacheSameFormulaReturnsSameInstance,
131+
testParseWithCacheDifferentFormulasReturnsDifferentInstances,
132+
testParseWithCacheStringLeafReturnsFunctionBase,
133+
testParseWithCacheNestedFunctionReturnsFunctionBase,
134+
testParseWithCacheDiyExpressionReturnsFunctionBase,
135+
testParseWithoutErrorWithCacheCachesResult,
136+
testParseCacheInvalidFormulaReturnsNull,
137+
testParseCacheCanEvaluate,
138+
runAllTests
139+
};

‎JavaScript/tests/AlgorithmEngineTest_csharp.js‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,47 @@ function testHash() {
178178
dt = engine.TryEvaluate("HmacSha512('&=我中国人 >||','12')", "");
179179
assert.strictEqual(dt, "4E9CE785C46569965C7C712A841EC7382C64D918D49F992EDB3504BED9C3A5EFBB1C8F712968F6B904417E07F9D72E707FCF148D55A4D3EDF1A9866B7BAC2049");
180180

181+
// 补充 '123' 系列
182+
dt = engine.TryEvaluate("Md5('123')", "");
183+
assert.strictEqual(dt, "202CB962AC59075B964B07152D234B70", "Md5('123') 应该是 '202CB962AC59075B964B07152D234B70'");
184+
185+
dt = engine.TryEvaluate("Sha1('123')", "");
186+
assert.strictEqual(dt, "40BD001563085FC35165329EA1FF5C5ECBDBBEEF", "Sha1('123') 应该是 '40BD001563085FC35165329EA1FF5C5ECBDBBEEF'");
187+
188+
dt = engine.TryEvaluate("Sha256('123')", "");
189+
assert.strictEqual(dt, "A665A45920422F9D417E4867EFDC4FB8A04A1F3FFF1FA07E998E86F7F7A27AE3", "Sha256('123') 应该是 'A665A45920422F9D417E4867EFDC4FB8A04A1F3FFF1FA07E998E86F7F7A27AE3'");
190+
191+
dt = engine.TryEvaluate("Sha512('&=我中国人 >||')", "");
192+
assert.strictEqual(dt, "FFEAC98C39D76CD86A3AB8ECEF16BE23166F68E1A3C5C9809A8AD2CE417170465286E4CF6FFA17924613CD7477533B9109A5DD504A2462F9DB693D56AD365C14", "Sha512('&=我中国人 >||') 应该有正确的 Sha512 值");
193+
194+
dt = engine.TryEvaluate("Sha512('123')", "");
195+
assert.strictEqual(dt, "3C9909AFEC25354D551DAE21590BB26E38D53F2173B8D3DC3EEE4C047E7AB1C1EB8B85103E3BE7BA613B31BB5C9C36214DC9F14A42FD7A2FDB84856BCA5C44C2", "Sha512('123') 应该是 '3C9909AFEC25354D551DAE21590BB26E38D53F2173B8D3DC3EEE4C047E7AB1C1EB8B85103E3BE7BA613B31BB5C9C36214DC9F14A42FD7A2FDB84856BCA5C44C2'");
196+
197+
dt = engine.TryEvaluate("HmacMd5('123','123')", "");
198+
assert.strictEqual(dt, "B2A1EC0F3E0607099D7F39791C04E9A4", "HmacMd5('123','123') 应该是 'B2A1EC0F3E0607099D7F39791C04E9A4'");
199+
200+
dt = engine.TryEvaluate("HmacSha1('123','123')", "");
201+
assert.strictEqual(dt, "A3C024F01CCCB3B63457D848B0D2F89C1F744A3D", "HmacSha1('123','123') 应该是 'A3C024F01CCCB3B63457D848B0D2F89C1F744A3D'");
202+
203+
dt = engine.TryEvaluate("HmacSha256('123','123')", "");
204+
assert.strictEqual(dt, "3CAFE40F92BE6AC77D2792B4B267C2DA11E3F3087B93BB19C6C5133786984B44", "HmacSha256('123','123') 应该是 '3CAFE40F92BE6AC77D2792B4B267C2DA11E3F3087B93BB19C6C5133786984B44'");
205+
206+
dt = engine.TryEvaluate("HmacSha512('123','123')", "");
207+
assert.strictEqual(dt, "0634FD04380BBAF5069C8C46A74C7D21DF7414888D980C27A16D5E262CB8C9059139C212D0926000FAF026E483904CEFAE2F5E9D9BD5F51FBC2AC4C4DE518115", "HmacSha512('123','123') 应该是 '0634FD04380BBAF5069C8C46A74C7D21DF7414888D980C27A16D5E262CB8C9059139C212D0926000FAF026E483904CEFAE2F5E9D9BD5F51FBC2AC4C4DE518115'");
208+
209+
// 方法式调用
210+
dt = engine.TryEvaluate("'123'.MD5()", "");
211+
assert.strictEqual(dt, "202CB962AC59075B964B07152D234B70", "'123'.MD5() 应该是 '202CB962AC59075B964B07152D234B70'");
212+
213+
dt = engine.TryEvaluate("'123'.SHA1()", "");
214+
assert.strictEqual(dt, "40BD001563085FC35165329EA1FF5C5ECBDBBEEF", "'123'.SHA1() 应该是 '40BD001563085FC35165329EA1FF5C5ECBDBBEEF'");
215+
216+
dt = engine.TryEvaluate("'123'.SHA256()", "");
217+
assert.strictEqual(dt, "A665A45920422F9D417E4867EFDC4FB8A04A1F3FFF1FA07E998E86F7F7A27AE3", "'123'.SHA256() 应该是 'A665A45920422F9D417E4867EFDC4FB8A04A1F3FFF1FA07E998E86F7F7A27AE3'");
218+
219+
dt = engine.TryEvaluate("'123'.SHA512()", "");
220+
assert.strictEqual(dt, "3C9909AFEC25354D551DAE21590BB26E38D53F2173B8D3DC3EEE4C047E7AB1C1EB8B85103E3BE7BA613B31BB5C9C36214DC9F14A42FD7A2FDB84856BCA5C44C2", "'123'.SHA512() 应该是 '3C9909AFEC25354D551DAE21590BB26E38D53F2173B8D3DC3EEE4C047E7AB1C1EB8B85103E3BE7BA613B31BB5C9C36214DC9F14A42FD7A2FDB84856BCA5C44C2'");
221+
181222
console.log('Hash 测试通过!');
182223
}
183224

0 commit comments

Comments
 (0)