202 lines
6.1 KiB
JavaScript
202 lines
6.1 KiB
JavaScript
const test = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const { spawnSync } = require('node:child_process');
|
|
const path = require('node:path');
|
|
|
|
const scriptPath = path.join(process.cwd(), 'scripts/gpc_sms_helper_macos.py');
|
|
|
|
function runPython(args, options = {}) {
|
|
for (const command of ['python3', 'python']) {
|
|
const result = spawnSync(command, args, {
|
|
encoding: 'utf8',
|
|
...options,
|
|
env: {
|
|
...process.env,
|
|
PYTHONIOENCODING: 'utf-8',
|
|
...(options.env || {}),
|
|
},
|
|
});
|
|
if (result.error && result.error.code === 'ENOENT') {
|
|
continue;
|
|
}
|
|
if (process.platform === 'win32' && result.status === 9009) {
|
|
continue;
|
|
}
|
|
return result;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
test('GPC SMS helper shows macOS and iPhone forwarding guidance on non-macOS', () => {
|
|
const help = runPython([scriptPath, '--help']);
|
|
if (!help) {
|
|
return;
|
|
}
|
|
assert.equal(help.status, 0);
|
|
if (process.platform === 'darwin') {
|
|
return;
|
|
}
|
|
const run = runPython([scriptPath, '--db', '/tmp/nonexistent-gpc-chat.db'], {
|
|
timeout: 3000,
|
|
});
|
|
assert.ok(run);
|
|
assert.notEqual(run.status, 0);
|
|
assert.match(run.stderr, /仅支持 macOS/);
|
|
assert.match(run.stderr, /iPhone 短信已转发|短信转发/);
|
|
});
|
|
|
|
test('GPC SMS helper filters cached OTP records by order timestamp', () => {
|
|
const code = `
|
|
import importlib.util
|
|
import json
|
|
|
|
script_path = ${JSON.stringify(scriptPath)}
|
|
spec = importlib.util.spec_from_file_location("gpc_sms_helper_macos", script_path)
|
|
module = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(module)
|
|
|
|
old = {"otp": "111111", "code": "111111", "message_id": "old", "received_at": "2026-05-05T00:00:00+00:00"}
|
|
fresh = {"otp": "222222", "code": "222222", "message_id": "fresh", "received_at": "2026-05-05T00:00:10+00:00"}
|
|
state = {"last_otp": fresh, "otps": [fresh, old]}
|
|
payload = {
|
|
"without_filter": module.select_otp_record(state, 0)["otp"],
|
|
"fresh_only": module.select_otp_record(state, module.parse_timestamp_ms("2026-05-05T00:00:05+00:00"))["otp"],
|
|
"none_after_fresh": module.select_otp_record(state, module.parse_timestamp_ms("2026-05-05T00:00:11+00:00")) is None,
|
|
}
|
|
print(json.dumps(payload))
|
|
`;
|
|
const run = runPython(['-c', code], {
|
|
timeout: 3000,
|
|
env: { GPC_SMS_HELPER_ALLOW_NON_MAC: '1' },
|
|
});
|
|
if (!run) {
|
|
return;
|
|
}
|
|
assert.equal(run.status, 0, run.stderr);
|
|
assert.deepEqual(JSON.parse(run.stdout.trim()), {
|
|
without_filter: '222222',
|
|
fresh_only: '222222',
|
|
none_after_fresh: true,
|
|
});
|
|
});
|
|
|
|
test('GPC SMS helper selects and consumes cached OTP records by phone', () => {
|
|
const code = `
|
|
import importlib.util
|
|
import json
|
|
|
|
script_path = ${JSON.stringify(scriptPath)}
|
|
spec = importlib.util.spec_from_file_location("gpc_sms_helper_macos", script_path)
|
|
module = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(module)
|
|
|
|
record_a = {
|
|
"otp": "111111",
|
|
"code": "111111",
|
|
"message_id": "a",
|
|
"rowid": 1,
|
|
"phone_e164": "+8615808505050",
|
|
"account_phone": "+8615808505050",
|
|
"received_at": "2026-05-05T00:00:00+00:00",
|
|
}
|
|
record_b = {
|
|
"otp": "222222",
|
|
"code": "222222",
|
|
"message_id": "b",
|
|
"rowid": 2,
|
|
"phone_e164": "+8618984829950",
|
|
"account_phone": "+8618984829950",
|
|
"received_at": "2026-05-05T00:00:10+00:00",
|
|
}
|
|
module.STATE.update({"last_otp": record_b, "otps": [record_b, record_a]})
|
|
selected_a = module.select_otp_record(module.get_state(), phone="+8615808505050")
|
|
module.consume_otp_record(phone="+8615808505050", record=selected_a)
|
|
state_after = module.get_state()
|
|
payload = {
|
|
"selected_a": selected_a["otp"],
|
|
"selected_b_after": module.select_otp_record(state_after, phone="+8618984829950")["otp"],
|
|
"selected_a_after": module.select_otp_record(state_after, phone="+8615808505050") is None,
|
|
"global_after": module.select_otp_record(state_after)["otp"],
|
|
}
|
|
print(json.dumps(payload))
|
|
`;
|
|
const run = runPython(['-c', code], {
|
|
timeout: 3000,
|
|
env: { GPC_SMS_HELPER_ALLOW_NON_MAC: '1' },
|
|
});
|
|
if (!run) {
|
|
return;
|
|
}
|
|
assert.equal(run.status, 0, run.stderr);
|
|
assert.deepEqual(JSON.parse(run.stdout.trim()), {
|
|
selected_a: '111111',
|
|
selected_b_after: '222222',
|
|
selected_a_after: true,
|
|
global_after: '222222',
|
|
});
|
|
});
|
|
|
|
test('GPC SMS helper consume keeps newer same-phone OTP when consuming an older record', () => {
|
|
const code = `
|
|
import importlib.util
|
|
import json
|
|
|
|
script_path = ${JSON.stringify(scriptPath)}
|
|
spec = importlib.util.spec_from_file_location("gpc_sms_helper_macos", script_path)
|
|
module = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(module)
|
|
|
|
record_old = {
|
|
"otp": "111111",
|
|
"code": "111111",
|
|
"message_id": "old",
|
|
"rowid": 1,
|
|
"phone_e164": "+8613800138000",
|
|
"account_phone": "+8613800138000",
|
|
"received_at": "2026-05-05T00:00:00+00:00",
|
|
}
|
|
record_new = {
|
|
"otp": "222222",
|
|
"code": "222222",
|
|
"message_id": "new",
|
|
"rowid": 2,
|
|
"phone_e164": "+8613800138000",
|
|
"account_phone": "+8613800138000",
|
|
"received_at": "2026-05-05T00:00:10+00:00",
|
|
}
|
|
record_other = {
|
|
"otp": "333333",
|
|
"code": "333333",
|
|
"message_id": "other",
|
|
"rowid": 3,
|
|
"phone_e164": "+8618984829950",
|
|
"account_phone": "+8618984829950",
|
|
"received_at": "2026-05-05T00:00:20+00:00",
|
|
}
|
|
module.STATE.update({"last_otp": record_new, "otps": [record_new, record_old, record_other]})
|
|
module.consume_otp_record(phone="+8613800138000", record=record_old)
|
|
state_after = module.get_state()
|
|
payload = {
|
|
"same_phone_after": module.select_otp_record(state_after, phone="+8613800138000")["otp"],
|
|
"other_phone_after": module.select_otp_record(state_after, phone="+8618984829950")["otp"],
|
|
"records_after": [item["message_id"] for item in state_after.get("otps", [])],
|
|
"global_after": module.select_otp_record(state_after)["otp"],
|
|
}
|
|
print(json.dumps(payload))
|
|
`;
|
|
const run = runPython(['-c', code], {
|
|
timeout: 3000,
|
|
env: { GPC_SMS_HELPER_ALLOW_NON_MAC: '1' },
|
|
});
|
|
if (!run) {
|
|
return;
|
|
}
|
|
assert.equal(run.status, 0, run.stderr);
|
|
assert.deepEqual(JSON.parse(run.stdout.trim()), {
|
|
same_phone_after: '222222',
|
|
other_phone_after: '333333',
|
|
records_after: ['new', 'other'],
|
|
global_after: '222222',
|
|
});
|
|
});
|