Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✅ add test for ideal TLAs #274

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions scripts/check-delegates-test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@ const twoLetter = `Chris de Almeida (CDA)\nRob Palmer (RP)\nUjjwal Sharma (USA)`
const threeLetter = `Chris de Almeida (CDA)\nRob Palmer (ROBPALMER)\nUjjwal Sharma (USA)`;
const duplicate = `Chris de Almeida (CDA)\nRob Palmer (RPR)\nUjjwal Sharma (USA)\nUjjwal Sharma (USA)`;
const valid = `Chris de Almeida (CDA)\nMichael Ficarra (MF)\nRob Palmer (RPR)\nUjjwal Sharma (USA)`;
const mononymous = `Chris de Almeida (CDA)\nYee (YEE)\nRob Palmer (RPR)\nUjjwal Sharma (USA)`;
const idealTLA = `Chris de Almeida (CAA)\nMichael Ficarra (MF)\nRob Palmer (RPR)\nUjjwal Sharma (USA)`;

assert.throws(() => checkDelegates(lex), { message: 'Line 3: Not in lexicographic order.' }); // also validates expected line number
assert.throws(() => checkDelegates(missing), { message: /Missing abbreviation for/ });
assert.throws(() => checkDelegates(uppercaseLatin), { message: /Abbreviations must be all uppercase Latin letters/ });
assert.throws(() => checkDelegates(twoLetter), { message: /not in allowlist. New delegate abbreviations must be three letters/ });
assert.throws(() => checkDelegates(threeLetter), { message: /New delegate abbreviations must be three letters/ });
assert.throws(() => checkDelegates(duplicate), { message: /Conflicting usage on line/ });
assert.throws(() => checkDelegates(mononymous), { message: /Unexpected mononymous delegate/ });
assert.throws(() => checkDelegates(idealTLA), { message: /Should be using ideal TLA \(CDA\)/ });

assert.doesNotThrow(() => checkDelegates(valid));
79 changes: 76 additions & 3 deletions scripts/check-delegates.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,16 @@

import fs from 'fs';

export function checkDelegates(contents = fs.readFileSync('./delegates.txt', 'utf8').toString()) {
export function checkDelegates(contents) {

const DELEGATES_FILE_PATH = './delegates.txt';

let isContentsDelegatesFile = false;

if (!contents) {
contents = fs.readFileSync(DELEGATES_FILE_PATH, 'utf8').toString();
isContentsDelegatesFile = true;
}

console.debug('checking delegates...');

Expand All @@ -19,8 +28,36 @@ export function checkDelegates(contents = fs.readFileSync('./delegates.txt', 'ut
'VM', 'WH', 'YK', 'ZB',
]);

// list of abbreviations that are not ideal.
// most of these are here because they are grandfathered in.
// new elements should only be false positives.
const NON_IDEAL_ABBRS = new Set([
michaelficarra marked this conversation as resolved.
Show resolved Hide resolved
'ABU', 'ACB', 'AEC', 'AEH', 'ALH', 'ARB', 'ASH', 'AVC', 'AVK',
'AVP', 'AWB', 'AYS', 'BNG', 'BRK', 'CCN', 'CHU', 'CJI', 'CJR',
'CJT', 'CZW', 'DAS', 'DDC', 'DEN', 'DFS', 'DFV', 'DHC', 'DJF',
'DJW', 'DLM', 'DMM', 'DMP', 'DTL', 'DVE', 'EDB', 'FED', 'FRT',
'FYT', 'GCW', 'GKZ', 'GPT', 'GRS', 'HUG', 'HUX', 'IOA', 'IVH',
'JAN', 'JAZ', 'JBS', 'JDD', 'JFP', 'JHJ', 'JHL', 'JMN', 'JPB',
'JPG', 'JRB', 'JSL', 'JSW', 'JTO', 'JXF', 'JXZ', 'JZY', 'KBK',
'KCD', 'KGO', 'KHG', 'KOT', 'KZM', 'LCA', 'LCP', 'LEO', 'LFP',
'LGY', 'LIU', 'LWT', 'LWW', 'LZH', 'LZJ', 'LZM', 'MAG', 'MAR',
'MCM', 'MCW', 'MED', 'MGR', 'MHA', 'MJN', 'MJS', 'MLS', 'MPC',
'MQW', 'MWS', 'MYC', 'MZG', 'NLY', 'PFC', 'PFM', 'PLH', 'PMD',
'PZE', 'REK', 'ROF', 'RTM', 'SFC', 'SJL', 'SJY', 'SMK', 'SNS',
'SRK', 'SRL', 'SSA', 'STH', 'SYH', 'SYP', 'SZH', 'SZT', 'TAB',
'TEK', 'TJC', 'TOC', 'TVC', 'WES', 'WMM', 'WWW', 'WXK', 'WYJ',
'XAX', 'XTY', 'XWC', 'YIY', 'YJM', 'YKL', 'YKZ', 'YRL', 'YTX',
'YYC', 'ZJL', 'ZRJ', 'ZYY',
]);

// delegates with only one name. this list should be as close to zero as possible...
const MONONYMOUS = new Set([
'Surma',
]);

const allAbbrs = new Set(contents.match(/(?<=\()[^)]*(?=\))/g));

const re = /^(?<name>[^(]+)(?: \((?<abbr>[^)]*)\))?$/;
const re = /^(?<firstName>[^( ]+) ?(?<lastName>[^(]+)?(?: \((?<abbr>[^)]*)\))?$/;
const abbrs = new Map;
const lines = contents.split('\n');

Expand All @@ -30,7 +67,7 @@ export function checkDelegates(contents = fs.readFileSync('./delegates.txt', 'ut
for (const line of lines) {
if (line.length === 0) continue;
const match = re.exec(line);
const { abbr } = match.groups;
const { abbr, firstName, lastName } = match.groups;

if (previousLine.localeCompare(line, 'en') > 0) {
throw new Error(`Line ${lineNumber}: Not in lexicographic order.`);
Expand All @@ -57,9 +94,45 @@ export function checkDelegates(contents = fs.readFileSync('./delegates.txt', 'ut
}
abbrs.set(abbr, lineNumber);

const idealTLA = getIdealTLA(firstName, lastName);

if (idealTLA){
if (!allAbbrs.has(idealTLA) && !NON_IDEAL_ABBRS.has(abbr) && !TWO_LETTER_ABBRS.has(abbr)){ // duplicates the 2-letter check, but helpful to distinguish these issues
throw new Error(`Line ${lineNumber}: Should be using ideal TLA (${idealTLA}). Note: because code cannot distinguish between a middle name vs a two-part last name, this may be a false positive.`);
}
} else if (!MONONYMOUS.has(firstName)) {
throw new Error(`Line ${lineNumber}: Unexpected mononymous delegate.`);
}

previousLine = line;
++lineNumber;
}

if (isContentsDelegatesFile) {

for (const abbr of TWO_LETTER_ABBRS) {
if (!allAbbrs.has(abbr)){
throw new Error(`abbreviation ${abbr} is included in TWO_LETTER_ABBRS, but does not exist in ${DELEGATES_FILE_PATH}`);
}
}

for (const abbr of NON_IDEAL_ABBRS) {
if (!allAbbrs.has(abbr)){
throw new Error(`abbreviation ${abbr} is included in NON_IDEAL_ABBRS, but does not exist in ${DELEGATES_FILE_PATH}`);
}
}

}

console.debug('...delegates are valid\n');
}

function getIdealTLA(firstName, lastName) {

if (lastName) {
return `${firstName.slice(0, 1)}${lastName.slice(0, 1)}${lastName.slice(lastName.length - 1)}`.toUpperCase();
}

return null;

}
Loading