- Replaced real names/companies with generic placeholders - Tests: Vainplex GmbH → Acme GmbH - README: Sebastian/Mondo Gate → Alex/Acme Corp - Author: OpenClaw Community - License: OpenClaw Contributors
123 lines
4.7 KiB
TypeScript
123 lines
4.7 KiB
TypeScript
// test/patterns.test.ts
|
|
|
|
import { describe, it } from 'node:test';
|
|
import * as assert from 'node:assert';
|
|
import { REGEX_PATTERNS } from '../src/patterns.js';
|
|
|
|
type TestCase = [string, string | null | string[]];
|
|
|
|
const runTestCases = (regex: RegExp, testCases: TestCase[]) => {
|
|
for (const [input, expected] of testCases) {
|
|
// Reset regex state for each test case
|
|
regex.lastIndex = 0;
|
|
const matches = input.match(regex);
|
|
if (expected === null) {
|
|
assert.strictEqual(matches, null, `Expected no match for: "${input}"`);
|
|
} else if (Array.isArray(expected)) {
|
|
assert.deepStrictEqual(matches, expected, `Mismatch for: "${input}"`);
|
|
} else {
|
|
assert.deepStrictEqual(matches, [expected], `Mismatch for: "${input}"`);
|
|
}
|
|
}
|
|
};
|
|
|
|
describe('REGEX_PATTERNS', () => {
|
|
|
|
it('should match valid email addresses', () => {
|
|
const testCases: TestCase[] = [
|
|
['contact support at support@example.com', 'support@example.com'],
|
|
['my email is john.doe123@sub.domain.co.uk.', 'john.doe123@sub.domain.co.uk'],
|
|
['invalid-email@', null],
|
|
['user@localhost', null],
|
|
['test@.com', null],
|
|
['multiple emails: a@b.com and c@d.org', ['a@b.com', 'c@d.org']],
|
|
];
|
|
runTestCases(REGEX_PATTERNS.email, testCases);
|
|
});
|
|
|
|
it('should match valid URLs', () => {
|
|
const testCases: TestCase[] = [
|
|
['visit https://www.example.com for more info', 'https://www.example.com'],
|
|
['check http://sub.domain.org/path?query=1', 'http://sub.domain.org/path?query=1'],
|
|
['ftp://invalid.com', null],
|
|
['www.example.com', null],
|
|
['a link: https://a.co and another http://b.com/end.', ['https://a.co', 'http://b.com/end']],
|
|
];
|
|
runTestCases(REGEX_PATTERNS.url, testCases);
|
|
});
|
|
|
|
it('should match ISO 8601 dates', () => {
|
|
const testCases: TestCase[] = [
|
|
['The date is 2026-02-17.', '2026-02-17'],
|
|
['Timestamp: 2026-02-17T15:30:00Z', '2026-02-17T15:30:00Z'],
|
|
['With milliseconds: 2026-02-17T15:30:00.123Z', '2026-02-17T15:30:00.123Z'],
|
|
['Not a date: 2026-02-17T', null],
|
|
['Invalid format 2026/02/17', null],
|
|
];
|
|
runTestCases(REGEX_PATTERNS.iso_date, testCases);
|
|
});
|
|
|
|
it('should match common date formats (US & EU)', () => {
|
|
const testCases: TestCase[] = [
|
|
['US date: 02/17/2026.', '02/17/2026'],
|
|
['EU date: 17.02.2026,', '17.02.2026'],
|
|
['Short year: 1.1.99', '1.1.99'],
|
|
['Two dates: 12/25/2024 and 24.12.2024', ['12/25/2024', '24.12.2024']],
|
|
];
|
|
runTestCases(REGEX_PATTERNS.common_date, testCases);
|
|
});
|
|
|
|
it('should match German date formats', () => {
|
|
const testCases: TestCase[] = [
|
|
['Datum: 17. Februar 2026', '17. Februar 2026'],
|
|
['Am 1. Januar 2025 war es kalt.', '1. Januar 2025'],
|
|
['No match: 17 Februar 2026', null],
|
|
];
|
|
runTestCases(REGEX_PATTERNS.german_date, testCases);
|
|
});
|
|
|
|
it('should match English date formats', () => {
|
|
const testCases: TestCase[] = [
|
|
['Date: February 17, 2026', 'February 17, 2026'],
|
|
['On March 1st, 2025, we launched.', 'March 1st, 2025'],
|
|
['Also August 2nd, 2024 and May 3rd, 2023.', ['August 2nd, 2024', 'May 3rd, 2023']],
|
|
['No match: February 17 2026', null],
|
|
];
|
|
runTestCases(REGEX_PATTERNS.english_date, testCases);
|
|
});
|
|
|
|
it('should match proper nouns (names, places)', () => {
|
|
const testCases: TestCase[] = [
|
|
['Hello, my name is Claude Keller.', ['Claude Keller']],
|
|
['This is Jean-Luc Picard of the USS Enterprise.', ['Jean-Luc Picard', 'USS Enterprise']],
|
|
['Talk to O\'Malley about it.', ['O\'Malley']],
|
|
['OpenClaw is a project.', ['OpenClaw']],
|
|
['Not a name: lower case', null],
|
|
['Multiple: Forge and Atlas are agents.', ['Forge', 'Atlas']],
|
|
];
|
|
runTestCases(REGEX_PATTERNS.proper_noun, testCases);
|
|
});
|
|
|
|
it('should match product-like names', () => {
|
|
const testCases: TestCase[] = [
|
|
['I have an iPhone 15.', 'iPhone 15'],
|
|
['We are using Windows 11.', 'Windows 11'],
|
|
['The latest model is GPT-4.', 'GPT-4'],
|
|
['Also look at ProductX.', 'ProductX'],
|
|
['The Roman Empire used IV.', 'Roman Empire used IV'], // Imperfect but acceptable
|
|
];
|
|
runTestCases(REGEX_PATTERNS.product_name, testCases);
|
|
});
|
|
|
|
it('should match organization names with suffixes', () => {
|
|
const testCases: TestCase[] = [
|
|
['He works at Acme GmbH.', 'Acme GmbH'],
|
|
['The owner of Stark Industries, LLC is Tony Stark.', 'Stark Industries, LLC'],
|
|
['Globex Corp. is another example.', 'Globex Corp.'],
|
|
['This also catches Acme Inc. and Cyberdyne Systems Ltd.', ['Acme Inc.', 'Cyberdyne Systems Ltd.']],
|
|
['No match for Acme alone', null],
|
|
];
|
|
runTestCases(REGEX_PATTERNS.organization_suffix, testCases);
|
|
});
|
|
|
|
});
|