@@ -330,3 +330,141 @@ fn check_llvm_and_get_config() -> Result<String> {
330330
331331 Ok ( llvm_config)
332332}
333+
334+ #[ cfg( test) ]
335+ mod tests {
336+ use super :: { copy_aflplusplus_submodule, remove_aflplusplus_dir, update_to_stable_or_tag} ;
337+ use crate :: { common, config:: is_repo} ;
338+ use anyhow:: Result ;
339+ use assert_cmd:: cargo:: CommandCargoExt ;
340+ use std:: { path:: Path , process:: Command } ;
341+ use tempfile:: tempdir;
342+
343+ #[ derive( Clone , Copy , Debug ) ]
344+ enum State {
345+ Nonexistent ,
346+ Submodule ,
347+ Tag ( & ' static str ) ,
348+ Stable ,
349+ }
350+
351+ const TESTCASES : & [ ( State , State , & [ & str ] ) ] = & [
352+ // smoelius: There is currently no way to update to the submodule.
353+ // (State::Nonexistent, State::Submodule, &[]),
354+ (
355+ State :: Nonexistent ,
356+ State :: Tag ( "v4.33c" ) ,
357+ & [
358+ #[ cfg( not( target_os = "macos" ) ) ]
359+ "Note: switching to 'v4.33c'." ,
360+ "HEAD is now at" ,
361+ ] ,
362+ ) ,
363+ (
364+ State :: Nonexistent ,
365+ State :: Stable ,
366+ & [
367+ #[ cfg( not( target_os = "macos" ) ) ]
368+ "Note: switching to 'origin/stable'." ,
369+ "HEAD is now at" ,
370+ ] ,
371+ ) ,
372+ (
373+ State :: Submodule ,
374+ State :: Tag ( "v4.33c" ) ,
375+ & [
376+ #[ cfg( not( target_os = "macos" ) ) ]
377+ "Note: switching to 'v4.33c'." ,
378+ "HEAD is now at" ,
379+ ] ,
380+ ) ,
381+ (
382+ State :: Submodule ,
383+ State :: Stable ,
384+ & [
385+ #[ cfg( not( target_os = "macos" ) ) ]
386+ "Note: switching to 'origin/stable'." ,
387+ "HEAD is now at" ,
388+ ] ,
389+ ) ,
390+ // smoelius: It should be possible to go from a tag to the stable version.
391+ (
392+ State :: Tag ( "v4.33c" ) ,
393+ State :: Stable ,
394+ & [ "Previous HEAD position was" , "HEAD is now at" ] ,
395+ ) ,
396+ // smoelius: It should be possible to go from the stable version to a tag.
397+ (
398+ State :: Stable ,
399+ State :: Tag ( "v4.33c" ) ,
400+ & [ "Previous HEAD position was" , "HEAD is now at" ] ,
401+ ) ,
402+ ] ;
403+
404+ #[ test]
405+ fn update ( ) {
406+ let mut base_dir = common:: xdg_base_dir ( ) ;
407+
408+ for & ( before, after, line_prefixes) in TESTCASES {
409+ eprintln ! ( "{before:?} -> {after:?}" ) ;
410+
411+ let tempdir = tempdir ( ) . unwrap ( ) ;
412+
413+ // smoelius: Based on https://github.com/whitequark/rust-xdg/issues/44, the recommended
414+ // way of testing with a fake value of `XDG_DATA_HOME` seems to be manually overwriting
415+ // the `data_home` field in `xdg::BaseDirectories`.
416+ base_dir. data_home = Some ( tempdir. path ( ) . to_path_buf ( ) ) ;
417+
418+ let aflplusplus_dir = common:: aflplusplus_dir_from_base_dir ( & base_dir) . unwrap ( ) ;
419+
420+ assert ! ( aflplusplus_dir. starts_with( tempdir. path( ) ) ) ;
421+
422+ set_aflplusplus_dir_contents ( before, & aflplusplus_dir) . unwrap ( ) ;
423+
424+ let mut command = Command :: cargo_bin ( "cargo-afl" ) . unwrap ( ) ;
425+ command. args ( [ "afl" , "config" , "--update" ] ) ;
426+ command. env ( "XDG_DATA_HOME" , tempdir. path ( ) ) ;
427+ match after {
428+ State :: Nonexistent | State :: Submodule => unreachable ! ( ) ,
429+ State :: Tag ( tag) => {
430+ command. args ( [ "--tag" , tag] ) ;
431+ }
432+ State :: Stable => { }
433+ }
434+ let output = command. output ( ) . unwrap ( ) ;
435+ assert ! ( output. status. success( ) ) ;
436+ let stderr = String :: from_utf8 ( output. stderr ) . unwrap ( ) ;
437+ contains_expected_line_prefixes ( & stderr, line_prefixes) ;
438+ }
439+ }
440+
441+ fn set_aflplusplus_dir_contents ( state : State , aflplusplus_dir : & Path ) -> Result < ( ) > {
442+ let result = match state {
443+ State :: Nonexistent => remove_aflplusplus_dir ( aflplusplus_dir) ,
444+ State :: Submodule => copy_aflplusplus_submodule ( aflplusplus_dir) ,
445+ State :: Tag ( tag) => update_to_stable_or_tag ( aflplusplus_dir, Some ( tag) ) ,
446+ State :: Stable => update_to_stable_or_tag ( aflplusplus_dir, None ) ,
447+ } ;
448+ // smoelius: Sanity.
449+ assert ! (
450+ is_repo( aflplusplus_dir)
451+ . is_ok_and( |value| value == matches!( state, State :: Tag ( _) | State :: Stable ) )
452+ ) ;
453+ result
454+ }
455+
456+ fn contains_expected_line_prefixes ( stderr : & str , mut line_prefixes : & [ & str ] ) {
457+ for line in stderr. lines ( ) {
458+ if line_prefixes
459+ . first ( )
460+ . is_some_and ( |prefix| line. starts_with ( prefix) )
461+ {
462+ line_prefixes = & line_prefixes[ 1 ..] ;
463+ }
464+ }
465+ assert ! (
466+ line_prefixes. is_empty( ) ,
467+ "Could not find line prefix {line_prefixes:?}:\n ```\n {stderr}```"
468+ ) ;
469+ }
470+ }
0 commit comments