@@ -9,6 +9,7 @@ import { describe, expect, test } from "bun:test";
99import {
1010 array ,
1111 assert as fcAssert ,
12+ pre ,
1213 property ,
1314 string ,
1415 stringMatching ,
@@ -27,10 +28,13 @@ const slugArb = stringMatching(/^[a-z][a-z0-9-]{1,20}[a-z0-9]$/);
2728/** Non-empty strings for general args */
2829const nonEmptyStringArb = string ( { minLength : 1 , maxLength : 50 } ) ;
2930
31+ /** Non-empty strings without slashes (valid plain IDs) */
32+ const plainIdArb = nonEmptyStringArb . filter ( ( s ) => ! s . includes ( "/" ) ) ;
33+
3034describe ( "parsePositionalArgs properties" , ( ) => {
31- test ( "single arg: always returns it as logId with undefined targetArg" , async ( ) => {
35+ test ( "single arg without slashes: returns it as logId with undefined targetArg" , async ( ) => {
3236 await fcAssert (
33- property ( nonEmptyStringArb , ( input ) => {
37+ property ( plainIdArb , ( input ) => {
3438 const result = parsePositionalArgs ( [ input ] ) ;
3539 expect ( result . logId ) . toBe ( input ) ;
3640 expect ( result . targetArg ) . toBeUndefined ( ) ;
@@ -39,6 +43,29 @@ describe("parsePositionalArgs properties", () => {
3943 ) ;
4044 } ) ;
4145
46+ test ( "single arg org/project/logId: splits into target and logId" , async ( ) => {
47+ await fcAssert (
48+ property ( tuple ( slugArb , slugArb , logIdArb ) , ( [ org , project , logId ] ) => {
49+ const combined = `${ org } /${ project } /${ logId } ` ;
50+ const result = parsePositionalArgs ( [ combined ] ) ;
51+ expect ( result . targetArg ) . toBe ( `${ org } /${ project } ` ) ;
52+ expect ( result . logId ) . toBe ( logId ) ;
53+ } ) ,
54+ { numRuns : DEFAULT_NUM_RUNS }
55+ ) ;
56+ } ) ;
57+
58+ test ( "single arg with one slash: throws ContextError (missing log ID)" , async ( ) => {
59+ await fcAssert (
60+ property ( tuple ( slugArb , slugArb ) , ( [ org , project ] ) => {
61+ expect ( ( ) => parsePositionalArgs ( [ `${ org } /${ project } ` ] ) ) . toThrow (
62+ ContextError
63+ ) ;
64+ } ) ,
65+ { numRuns : DEFAULT_NUM_RUNS }
66+ ) ;
67+ } ) ;
68+
4269 test ( "two args: first is always targetArg, second is always logId" , async ( ) => {
4370 await fcAssert (
4471 property (
@@ -91,6 +118,9 @@ describe("parsePositionalArgs properties", () => {
91118 property (
92119 array ( nonEmptyStringArb , { minLength : 1 , maxLength : 3 } ) ,
93120 ( args ) => {
121+ // Skip single-arg with slashes — those throw ContextError (tested separately)
122+ pre ( args . length > 1 || ! args [ 0 ] ?. includes ( "/" ) ) ;
123+
94124 const result1 = parsePositionalArgs ( args ) ;
95125 const result2 = parsePositionalArgs ( args ) ;
96126 expect ( result1 ) . toEqual ( result2 ) ;
@@ -109,6 +139,9 @@ describe("parsePositionalArgs properties", () => {
109139 property (
110140 array ( nonEmptyStringArb , { minLength : 1 , maxLength : 3 } ) ,
111141 ( args ) => {
142+ // Skip single-arg with slashes — those throw ContextError (tested separately)
143+ pre ( args . length > 1 || ! args [ 0 ] ?. includes ( "/" ) ) ;
144+
112145 const result = parsePositionalArgs ( args ) ;
113146 expect ( result . logId ) . toBeDefined ( ) ;
114147 expect ( typeof result . logId ) . toBe ( "string" ) ;
@@ -118,10 +151,10 @@ describe("parsePositionalArgs properties", () => {
118151 ) ;
119152 } ) ;
120153
121- test ( "result targetArg is undefined for single arg, defined for multiple" , async ( ) => {
122- // Single arg case
154+ test ( "result targetArg is undefined for single slash-free arg, defined for multiple" , async ( ) => {
155+ // Single arg case (without slashes)
123156 await fcAssert (
124- property ( nonEmptyStringArb , ( input ) => {
157+ property ( plainIdArb , ( input ) => {
125158 const result = parsePositionalArgs ( [ input ] ) ;
126159 expect ( result . targetArg ) . toBeUndefined ( ) ;
127160 } ) ,
0 commit comments