Skip to content

Commit ed5563d

Browse files
feat: Switch to Commander for CLI Parsing
Avoids issues with manual arg parsing.
1 parent b3758d1 commit ed5563d

3 files changed

Lines changed: 64 additions & 75 deletions

File tree

samples/e2e-testcases/index.ts

Lines changed: 44 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*/
1010

1111
import { ClassifierSdk, ImageFormat, parseAudience } from '@crispthinking/athena-classifier-sdk';
12+
import { Command, Option, InvalidArgumentError } from 'commander';
1213
import fs from 'fs';
1314
import path from 'path';
1415
import { fileURLToPath } from 'url';
@@ -60,24 +61,40 @@ interface ImageComparisonResult {
6061
}
6162

6263
/**
63-
* Display usage information
64+
* CLI options interface
6465
*/
65-
function showUsage(): void {
66-
console.log(`
67-
🧪 Athena E2E Test Cases Runner
68-
69-
Usage:
70-
npx tsx index.ts [options]
71-
npm start [options]
72-
73-
Options:
74-
-h, --help Show this help message
75-
-t, --testset <name> Test set to run (default: integrator_sample)
76-
Valid: integrator_sample, benign_model, live_model
77-
-T, --tolerance <value> Comparison tolerance (default: 0.0001)
78-
-v, --verbose Enable verbose output
79-
-l, --list List available test sets and exit
66+
interface CliOptions {
67+
testset: TestSet;
68+
tolerance: number;
69+
verbose: boolean;
70+
list: boolean;
71+
}
8072

73+
/**
74+
* Setup and parse CLI arguments using commander
75+
*/
76+
function parseArgs(): CliOptions {
77+
const program = new Command();
78+
79+
program
80+
.name('athena-e2e-testcases')
81+
.description('Athena E2E Test Cases Runner\n\nRuns shared end-to-end test cases from athena-protobufs/testcases/ through the Athena classification service and validates results against expected outputs.')
82+
.version('1.0.0')
83+
.addOption(
84+
new Option('-t, --testset <name>', 'Test set to run')
85+
.choices(VALID_TESTSETS as readonly string[])
86+
.default('integrator_sample')
87+
)
88+
.option('-T, --tolerance <value>', 'Comparison tolerance', (value) => {
89+
const parsed = parseFloat(value);
90+
if (isNaN(parsed) || parsed < 0) {
91+
throw new InvalidArgumentError('Tolerance must be a positive number');
92+
}
93+
return parsed;
94+
}, 0.0001)
95+
.option('-v, --verbose', 'Enable verbose output', false)
96+
.option('-l, --list', 'List available test sets and exit', false)
97+
.addHelpText('after', `
8198
Environment Variables (Required):
8299
ATHENA_CLIENT_ID OAuth client ID
83100
ATHENA_CLIENT_SECRET OAuth client secret
@@ -89,64 +106,24 @@ Environment Variables (Optional):
89106
ATHENA_AUDIENCE OAuth audience (default: crisp-athena-live)
90107
91108
Examples:
92-
# Run default test set
93-
npx tsx index.ts
94-
95-
# Run specific test set with custom tolerance
96-
npx tsx index.ts --testset live_model --tolerance 0.01
97-
98-
# Verbose output
99-
npx tsx index.ts --verbose
109+
$ npx tsx index.ts
110+
$ npx tsx index.ts --testset live_model --tolerance 0.01
111+
$ npx tsx index.ts --verbose --list
100112
101113
Setup:
102-
# Create environment file
103114
cp ../.env.example ../.env
104-
# Edit ../.env with your credentials
105-
# Source with auto-export
106115
set -a && source ../.env && set +a
107116
`);
108-
}
109117

110-
/**
111-
* Parse command line arguments
112-
*/
113-
function parseArgs(): { testset: TestSet; tolerance: number; verbose: boolean; list: boolean; help: boolean } {
114-
const args = process.argv.slice(2);
115-
const options = {
116-
testset: 'integrator_sample' as TestSet,
117-
tolerance: 0.0001,
118-
verbose: false,
119-
list: false,
120-
help: false,
121-
};
118+
program.parse();
122119

123-
for (let i = 0; i < args.length; i++) {
124-
const arg = args[i];
125-
126-
if (arg === '-h' || arg === '--help') {
127-
options.help = true;
128-
} else if (arg === '-v' || arg === '--verbose') {
129-
options.verbose = true;
130-
} else if (arg === '-l' || arg === '--list') {
131-
options.list = true;
132-
} else if (arg === '-t' || arg === '--testset') {
133-
const value = args[++i] as TestSet;
134-
if (!VALID_TESTSETS.includes(value)) {
135-
console.error(`Error: Invalid test set '${value}'. Valid options: ${VALID_TESTSETS.join(', ')}`);
136-
process.exit(2);
137-
}
138-
options.testset = value;
139-
} else if (arg === '-T' || arg === '--tolerance') {
140-
const value = parseFloat(args[++i]);
141-
if (isNaN(value) || value < 0) {
142-
console.error('Error: Tolerance must be a positive number');
143-
process.exit(2);
144-
}
145-
options.tolerance = value;
146-
}
147-
}
148-
149-
return options;
120+
const opts = program.opts();
121+
return {
122+
testset: opts.testset as TestSet,
123+
tolerance: opts.tolerance as number,
124+
verbose: opts.verbose as boolean,
125+
list: opts.list as boolean,
126+
};
150127
}
151128

152129
/**
@@ -262,11 +239,6 @@ function compareResults(
262239
async function main(): Promise<void> {
263240
const options = parseArgs();
264241

265-
if (options.help) {
266-
showUsage();
267-
process.exit(0);
268-
}
269-
270242
if (options.list) {
271243
listTestSets();
272244
process.exit(0);

samples/e2e-testcases/package-lock.json

Lines changed: 11 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

samples/e2e-testcases/package.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,22 @@
99
"dev": "npx tsx index.ts --help"
1010
},
1111
"dependencies": {
12-
"@crispthinking/athena-classifier-sdk": "file:../../"
12+
"@crispthinking/athena-classifier-sdk": "file:../../",
13+
"commander": "^14.0.3"
1314
},
1415
"devDependencies": {
1516
"tsx": "^4.7.0"
1617
},
1718
"engines": {
1819
"node": ">=18.0.0"
1920
},
20-
"keywords": ["athena", "classification", "e2e", "testing", "validation"],
21+
"keywords": [
22+
"athena",
23+
"classification",
24+
"e2e",
25+
"testing",
26+
"validation"
27+
],
2128
"author": "Crisp Thinking",
2229
"license": "MIT"
2330
}

0 commit comments

Comments
 (0)