This commit is contained in:
@@ -9,16 +9,55 @@ async function read(relativePath) {
|
||||
return fs.readFile(path.join(root, relativePath), 'utf8');
|
||||
}
|
||||
|
||||
function normalizedTokens(line) {
|
||||
return line
|
||||
.trim()
|
||||
.replaceAll(',', ' ')
|
||||
.replaceAll(';', ' ')
|
||||
.replaceAll('(', ' ')
|
||||
.replaceAll(')', ' ')
|
||||
.split(' ')
|
||||
.map(token => token.trim().toUpperCase())
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
function routeTableLines(schema) {
|
||||
const lines = schema.split('\n');
|
||||
const start = lines.findIndex(line => normalizedTokens(line).join(' ') === 'CREATE TABLE IF NOT EXISTS ROUTES');
|
||||
assert.notEqual(start, -1, 'database/schema.sql must define the routes table');
|
||||
|
||||
const end = lines.findIndex((line, index) => index > start && normalizedTokens(line).includes('STRICT'));
|
||||
assert.notEqual(end, -1, 'the routes table must be declared STRICT');
|
||||
return lines.slice(start, end + 1);
|
||||
}
|
||||
|
||||
function hasActivatedAtTextDefaultNull(lines) {
|
||||
return lines.some(line => {
|
||||
const tokens = normalizedTokens(line);
|
||||
return tokens[0] === 'ACTIVATED_AT'
|
||||
&& tokens[1] === 'TEXT'
|
||||
&& tokens.includes('DEFAULT')
|
||||
&& tokens.includes('NULL');
|
||||
});
|
||||
}
|
||||
|
||||
function containsTokenSequence(sql, sequence) {
|
||||
const tokens = sql
|
||||
.split('\n')
|
||||
.flatMap(normalizedTokens);
|
||||
|
||||
return tokens.some((_, index) => sequence.every((token, offset) => tokens[index + offset] === token));
|
||||
}
|
||||
|
||||
test('initial database schema creates routes with a nullable activation timestamp', async () => {
|
||||
const schema = await read('database/schema.sql');
|
||||
const migration = await read('database/migrations/20260901_add_route_activated_at.sql');
|
||||
const routeTable = schema.match(/CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?routes\s*\([\s\S]*?\)\s+STRICT\s*;/i);
|
||||
const routes = routeTableLines(schema);
|
||||
|
||||
assert.ok(routeTable, 'database/schema.sql must define the routes table as a STRICT SQLite table');
|
||||
assert.match(routeTable[0], /\bactivated_at\s+TEXT\s+(?:NULL\s+)?DEFAULT\s+NULL\b/i);
|
||||
assert.doesNotMatch(routeTable[0], /\bactivated_at\s+DATETIME\b/i);
|
||||
|
||||
assert.match(migration, /ALTER\s+TABLE\s+routes\s+ADD\s+COLUMN\s+activated_at\s+TEXT\s+(?:NULL\s+)?DEFAULT\s+NULL/i);
|
||||
assert.doesNotMatch(migration, /\bactivated_at\s+DATETIME\b/i);
|
||||
assert.match(migration, /Neue Strecken bleiben unveröffentlicht|unpublished|activated_at is NULL/i);
|
||||
});
|
||||
assert.equal(hasActivatedAtTextDefaultNull(routes), true);
|
||||
assert.equal(containsTokenSequence(routes.join('\n'), ['ACTIVATED_AT', 'DATETIME']), false);
|
||||
assert.equal(containsTokenSequence(routes.join('\n'), ['ON', 'UPDATE', 'CURRENT_TIMESTAMP']), false);
|
||||
assert.equal(containsTokenSequence(migration, ['ALTER', 'TABLE', 'ROUTES', 'ADD', 'COLUMN', 'ACTIVATED_AT', 'TEXT']), true);
|
||||
assert.equal(containsTokenSequence(migration, ['ACTIVATED_AT', 'DATETIME']), false);
|
||||
assert.equal(migration.includes('activated_at is NULL'), true);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user