char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
688e96e
main
1use std:: io:: Write ; 2use std:: process::{ Command , Output , Stdio }; 3 4fn avril ( args : & [ & str ]) ->Output { 5let dir = tempfile:: tempdir (). unwrap (); 6 std:: fs:: write ( dir. path (). join ( "main.js" ), "console.log('ran');" ). unwrap (); 7Command :: new ( env! ( "CARGO_BIN_EXE_avril" )) 8. current_dir ( dir. path ()) 9. args ( args) 10. output () 11. unwrap () 12} 13 14fn stdout ( args : & [ & str ]) ->String { 15let output =avril ( args); 16assert! ( 17 output. status . success (), 18"{args:?}: {}" , 19String :: from_utf8_lossy ( & output. stderr ) 20); 21String :: from_utf8 ( output. stdout ). unwrap () 22} 23 24fn stderr ( args : & [ & str ]) ->String { 25let output =avril ( args); 26assert! ( !output. status . success (), "{args:?}" ); 27assert! ( output. stdout . is_empty (), "{args:?}" ); 28String :: from_utf8 ( output. stderr ). unwrap () 29} 30 31# [ test ] 32fn global_help_lists_commands_and_command_help_lists_only_their_options () { 33for argsin [ & [ "--help" ][ ..], & [ "-h" ], & [ "help" ], & [ "-0" , "--help" ]] { 34let help =stdout ( args); 35for ( heading, expected) in [ 36( 37"Main commands:\n" , 38& [ "repl" , "run" , "serve" , "task" , "test" ][ ..], 39), 40( 41"Additional commands:\n" , 42& [ 43"add" , "bundle" , "cache" , "check" , "info" , "lsp" , "update" , "vendor" , 44][ ..], 45), 46] { 47let commands: Vec < _ > = help 48. split_once ( heading) 49. unwrap () 50. 1 51. lines () 52. take_while ( |line| !line. is_empty ()) 53. map ( |line| line. split_whitespace (). next (). unwrap ()) 54. collect (); 55assert_eq! ( commands, expected, "{args:?}: {help}" ); 56} 57assert! ( 58 help. find ( "Main commands:" ). unwrap () < help. find ( "Additional commands:" ). unwrap (), 59"{args:?}: {help}" 60); 61assert! ( !help. contains ( "--prune" ), "{help}" ); 62} 63for argsin [ 64& [ "help" , "update" ][ ..], 65& [ "update" , "--help" ], 66& [ "update" , "-h" , "main.js" ], 67] { 68let help =stdout ( args); 69assert! ( help. contains ( "Usage: avril update" ), "{help}" ); 70assert! ( help. contains ( "--prune" ), "{help}" ); 71assert! ( 72 !help. contains ( "--frozen" ) && !help. contains ( "--config" ), 73"{help}" 74); 75} 76let help =stdout ( & [ "help" , "task" ]); 77assert! ( 78 help. contains ( "Usage: avril task [--watch] [<name> [args...]]" ), 79"{help}" 80); 81assert! ( help. contains ( "--watch" ), "{help}" ); 82assert! ( stderr ( & [ "task" , "--bogus" ]). contains ( "Usage: avril task" )); 83let help =stdout ( & [ "help" , "add" ]); 84assert! ( help. contains ( "\nAdd:\n --config=PATH" ), "{help}" ); 85assert! ( help. contains ( "\nPackages:\n --offline" ), "{help}" ); 86assert! ( 87 !help. contains ( "--allow-" ) && !help. contains ( "--lock" ), 88"{help}" 89); 90assert! ( stderr ( & [ "help" , "nope" ]). contains ( "Unknown command: nope" )); 91assert! ( stderr ( & [ "editor" , "main.js" ]). contains ( "Unknown command: editor" )); 92assert! ( stderr ( & [ "help" , "editor" ]). contains ( "Unknown command: editor" )); 93} 94 95# [ test ] 96fn package_commands_expose_explicit_registry_options () { 97for commandin [ 98"run" , "repl" , "test" , "serve" , "cache" , "info" , "update" , "vendor" , "lsp" , "add" , 99] { 100let help =stdout ( & [ command, "--help" ]); 101assert! ( help. contains ( "--jsr-registry=URL" ), "{command}: {help}" ); 102assert! ( help. contains ( "--npm-registry=URL" ), "{command}: {help}" ); 103assert! ( !help. contains ( "--registry" ), "{command}: {help}" ); 104assert! ( 105stderr ( & [ command, "--registry=https://jsr.io/" ]). contains ( "Unknown option: --registry" ), 106"{command}" 107); 108} 109} 110 111# [ test ] 112fn lsp_exposes_live_project_policy_and_rejects_retired_options () { 113for argsin [ & [ "lsp" , "--help" ][ ..], & [ "help" , "lsp" ]] { 114let help =stdout ( args); 115assert! ( !help. contains ( "--experimental-project" )); 116assert! ( help. contains ( "--typescript=PATH" )); 117assert! ( help. contains ( "--project=DIR" ) && help. contains ( "--lock" )); 118} 119assert! ( stderr ( & [ "lsp" ]). contains ( "requires --typescript" )); 120assert! ( 121stderr ( & [ 122"lsp" , 123"--typescript=missing" , 124"--project=." , 125"--experimental-project=missing" 126]) 127. contains ( "Unknown option" ) 128); 129assert! ( stderr ( & [ "lsp" , "--allow-all" ]). contains ( "Unknown option" )); 130assert! ( stderr ( & [ "lsp" , "--typescript=a" , "--typescript=b" ]). contains ( "Duplicate option" )); 131} 132 133# [ test ] 134fn check_exposes_a_typescript_backend_and_requires_it () { 135for argsin [ & [ "check" , "--help" ][ ..], & [ "help" , "check" ]] { 136let help =stdout ( args); 137assert! ( 138 help. contains ( "Usage: avril check --typescript=PATH" ), 139"{help}" 140); 141assert! ( help. contains ( "--typescript=PATH" ), "{help}" ); 142assert! ( help. contains ( "--jsr-registry=URL" ), "{help}" ); 143assert! ( help. contains ( "--lock=PATH" ), "{help}" ); 144} 145assert! ( stderr ( & [ "check" , "main.js" ]). contains ( "check requires --typescript" )); 146assert! ( stderr ( & [ "check" ]). contains ( "check requires --typescript" )); 147assert! ( stderr ( & [ "check" , "--typescript=backend" ]). contains ( "Usage: avril check" )); 148assert! ( 149stderr ( & [ "check" , "--typescript=a" , "--typescript=b" , "main.js" ]) 150. contains ( "Duplicate option" ) 151); 152assert! ( 153stderr ( & [ "check" , "--project=." , "main.js" ]) 154. contains ( "--project is not an option of `avril check`" ) 155); 156assert! ( 157stderr ( & [ "run" , "--typescript=backend" , "main.js" ]) 158. contains ( "--typescript is not an option of `avril run`" ) 159); 160} 161 162# [ test ] 163fn commands_reject_options_they_do_not_take () { 164for ( args, message) in [ 165( 166& [ "run" , "--pre" , "main.js" ][ ..], 167"--pre is not an option of `avril run`" , 168), 169( & [ "main.js" ], "Unknown command: main.js" ), 170( & [ "-0" , "main.js" ], "The REPL does not accept a module" ), 171( & [ "--prune" ], "--prune is not an option of `avril repl`" ), 172( 173& [ "repl" , "--include=x" ], 174"--include is not an option of `avril repl`" , 175), 176( 177& [ "update" , "--frozen" , "main.js" ], 178"--frozen is not an option of `avril update`" , 179), 180( 181& [ "cache" , "--out=x" , "main.js" ], 182"--out is not an option of `avril cache`" , 183), 184( 185& [ "add" , "--lock=x" , "jsr:@test/pkg@1" ], 186"--lock is not an option of `avril add`" , 187), 188( 189& [ "add" , "-0" , "jsr:@test/pkg@1" ], 190"-0 is not an option of `avril add`" , 191), 192( & [ "run" , "--bogus" , "main.js" ], "Unknown option: --bogus" ), 193( 194& [ "run" , "--offline=yes" , "main.js" ], 195"--offline does not take a value" , 196), 197( 198& [ "add" , "--pre=yes" , "jsr:@test/pkg" ], 199"--pre does not take a value" , 200), 201( & [ "cache" ], "Usage: avril cache [OPTIONS] <module>" ), 202] { 203let error =stderr ( args); 204assert! ( error. contains ( message), "{args:?}: {error}" ); 205} 206assert_eq! ( stdout ( & [ "run" , "--" , "main.js" ]), "ran\n" ); 207} 208 209# [ test ] 210fn without_a_command_avril_only_starts_the_repl () { 211for argsin [ & [][ ..], & [ "-0" ]] { 212let mut child =Command :: new ( env! ( "CARGO_BIN_EXE_avril" )) 213. args ( args) 214. stdin ( Stdio :: piped ()) 215. stdout ( Stdio :: piped ()) 216. spawn () 217. unwrap (); 218 child. stdin . take (). unwrap (). write_all ( b"6 * 7\n" ). unwrap (); 219let output = child. wait_with_output (). unwrap (); 220assert! ( output. status . success (), "{args:?}" ); 221assert_eq! ( output. stdout , b"42\n" , "{args:?}" ); 222} 223}