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