13
13
#![ recursion_limit = "256" ]
14
14
#![ deny( missing_docs) ]
15
15
16
+ use anyhow:: { anyhow, Context , Result } ;
17
+ use garando_syntax as syntax;
18
+ use indoc:: writedoc;
16
19
use std:: collections:: { HashMap , HashSet } ;
17
20
use std:: env;
18
21
use std:: fs:: File ;
19
22
use std:: io:: prelude:: * ;
20
23
use std:: io:: BufWriter ;
21
24
use std:: path:: { Path , PathBuf } ;
22
25
use std:: rc:: Rc ;
23
-
24
- use garando_syntax as syntax;
25
- use indoc:: writedoc;
26
26
use syntax:: abi:: Abi ;
27
27
use syntax:: ast;
28
28
use syntax:: ast:: { Attribute , Name } ;
@@ -41,9 +41,6 @@ use syntax::ptr::P;
41
41
use syntax:: util:: small_vector:: SmallVector ;
42
42
use syntax:: visit:: { self , Visitor } ;
43
43
44
- type Error = Box < dyn std:: error:: Error > ;
45
- type Result < T , E = Error > = std:: result:: Result < T , E > ;
46
-
47
44
/// Programming language
48
45
#[ derive( Debug ) ]
49
46
pub enum Lang {
@@ -773,6 +770,17 @@ impl TestGenerator {
773
770
self
774
771
}
775
772
773
+ /// Generate all tests and panic on any errors.
774
+ ///
775
+ /// This function is a convenience wrapper around `try_generate` that panics instead of returning
776
+ /// errors.
777
+ ///
778
+ /// See `try_generate` for the error-handling version of this function.
779
+ pub fn generate < P : AsRef < Path > > ( & mut self , krate : P , out_file : & str ) {
780
+ self . try_generate ( krate, out_file)
781
+ . unwrap_or_else ( |e| panic ! ( "Failed to generate tests: {e}" ) ) ;
782
+ }
783
+
776
784
/// Generate all tests.
777
785
///
778
786
/// This function is first given the path to the `*-sys` crate which is
@@ -791,16 +799,16 @@ impl TestGenerator {
791
799
/// use ctest::TestGenerator;
792
800
///
793
801
/// let mut cfg = TestGenerator::new();
794
- /// cfg.generate ("../path/to/libfoo-sys/lib.rs", "all.rs");
802
+ /// cfg.try_generate ("../path/to/libfoo-sys/lib.rs", "all.rs");
795
803
/// ```
796
- pub fn generate < P : AsRef < Path > > ( & mut self , krate : P , out_file : & str ) {
804
+ pub fn try_generate < P : AsRef < Path > > ( & mut self , krate : P , out_file : & str ) -> Result < PathBuf > {
797
805
let krate = krate. as_ref ( ) ;
798
- let out = self . generate_files ( krate, out_file) ;
806
+ let out = self . generate_files ( krate, out_file) ? ;
799
807
800
- let target = self
801
- . target
802
- . clone ( )
803
- . unwrap_or_else ( || env :: var ( "TARGET" ) . unwrap ( ) ) ;
808
+ let target = match self . target . clone ( ) {
809
+ Some ( t ) => t ,
810
+ None => env :: var ( "TARGET" ) . context ( "TARGET environment variable not found" ) ? ,
811
+ } ;
804
812
805
813
// Compile our C shim to be linked into tests
806
814
let mut cfg = cc:: Build :: new ( ) ;
@@ -815,19 +823,19 @@ impl TestGenerator {
815
823
if target. contains ( "msvc" ) {
816
824
cfg. flag ( "/W3" ) . flag ( "/Wall" ) . flag ( "/WX" )
817
825
// ignored warnings
818
- . flag ( "/wd4820" ) // warning about adding padding?
819
- . flag ( "/wd4100" ) // unused parameters
820
- . flag ( "/wd4996" ) // deprecated functions
821
- . flag ( "/wd4296" ) // '<' being always false
822
- . flag ( "/wd4255" ) // converting () to (void)
823
- . flag ( "/wd4668" ) // using an undefined thing in preprocessor?
824
- . flag ( "/wd4366" ) // taking ref to packed struct field might be unaligned
825
- . flag ( "/wd4189" ) // local variable initialized but not referenced
826
- . flag ( "/wd4710" ) // function not inlined
827
- . flag ( "/wd5045" ) // compiler will insert Spectre mitigation
828
- . flag ( "/wd4514" ) // unreferenced inline function removed
829
- . flag ( "/wd4711" ) // function selected for automatic inline
830
- ;
826
+ . flag ( "/wd4820" ) // warning about adding padding?
827
+ . flag ( "/wd4100" ) // unused parameters
828
+ . flag ( "/wd4996" ) // deprecated functions
829
+ . flag ( "/wd4296" ) // '<' being always false
830
+ . flag ( "/wd4255" ) // converting () to (void)
831
+ . flag ( "/wd4668" ) // using an undefined thing in preprocessor?
832
+ . flag ( "/wd4366" ) // taking ref to packed struct field might be unaligned
833
+ . flag ( "/wd4189" ) // local variable initialized but not referenced
834
+ . flag ( "/wd4710" ) // function not inlined
835
+ . flag ( "/wd5045" ) // compiler will insert Spectre mitigation
836
+ . flag ( "/wd4514" ) // unreferenced inline function removed
837
+ . flag ( "/wd4711" ) // function selected for automatic inline
838
+ ;
831
839
} else {
832
840
cfg. flag ( "-Wall" )
833
841
. flag ( "-Wextra" )
@@ -851,25 +859,40 @@ impl TestGenerator {
851
859
cfg. include ( p) ;
852
860
}
853
861
854
- let stem = out. file_stem ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) ;
855
- cfg. target ( & target)
856
- . out_dir ( out. parent ( ) . unwrap ( ) )
857
- . compile ( & format ! ( "lib{stem}.a" ) ) ;
862
+ let stem = out
863
+ . file_stem ( )
864
+ . context ( "Failed to get file stem" ) ?
865
+ . to_str ( )
866
+ . context ( "Failed to convert to str" ) ?;
867
+
868
+ let parent = out
869
+ . parent ( )
870
+ . context ( "Output file has no parent directory" ) ?;
871
+
872
+ cfg. target ( & target) . out_dir ( parent) ;
873
+
874
+ let name = format ! ( "lib{stem}.a" ) ;
875
+
876
+ cfg. try_compile ( & name)
877
+ . context ( format ! ( "failed to compile `{}`" , name) )
878
+ . map ( |_| out)
858
879
}
859
880
860
881
#[ doc( hidden) ] // TODO: needs docs
861
- pub fn generate_files < P : AsRef < Path > > ( & mut self , krate : P , out_file : & str ) -> PathBuf {
882
+ pub fn generate_files < P : AsRef < Path > > ( & mut self , krate : P , out_file : & str ) -> Result < PathBuf > {
862
883
self . generate_files_impl ( krate, out_file)
863
- . expect ( "generation failed" )
864
884
}
865
885
866
886
fn generate_files_impl < P : AsRef < Path > > ( & mut self , krate : P , out_file : & str ) -> Result < PathBuf > {
867
887
let krate = krate. as_ref ( ) ;
888
+
868
889
// Prep the test generator
869
890
let out_dir = self
870
891
. out_dir
871
892
. clone ( )
872
- . unwrap_or_else ( || PathBuf :: from ( env:: var_os ( "OUT_DIR" ) . unwrap ( ) ) ) ;
893
+ . or_else ( || env:: var_os ( "OUT_DIR" ) . map ( PathBuf :: from) )
894
+ . context ( "Neither out_dir nor OUT_DIR environment variable is set" ) ?;
895
+
873
896
let out_file = out_dir. join ( out_file) ;
874
897
let ext = match self . lang {
875
898
Lang :: C => "c" ,
@@ -878,18 +901,26 @@ impl TestGenerator {
878
901
let c_file = out_file. with_extension ( ext) ;
879
902
let rust_out = BufWriter :: new ( File :: create ( & out_file) ?) ;
880
903
let c_out = BufWriter :: new ( File :: create ( & c_file) ?) ;
881
- let mut sess = ParseSess :: new ( FilePathMapping :: empty ( ) ) ;
904
+
882
905
let target = self
883
906
. target
884
907
. clone ( )
885
- . unwrap_or_else ( || env:: var ( "TARGET" ) . unwrap ( ) ) ;
908
+ . or_else ( || env:: var ( "TARGET" ) . ok ( ) )
909
+ . filter ( |t| !t. is_empty ( ) )
910
+ . context ( "TARGET environment variable not set or empty" ) ?;
911
+
912
+ let mut sess = ParseSess :: new ( FilePathMapping :: empty ( ) ) ;
886
913
for ( k, v) in default_cfg ( & target) . into_iter ( ) . chain ( self . cfg . clone ( ) ) {
887
914
let s = |s : & str | Name :: intern ( s) ;
888
915
sess. config . insert ( ( s ( & k) , v. as_ref ( ) . map ( |n| s ( n) ) ) ) ;
889
916
}
890
917
891
- // Parse the libc crate
892
- let krate = parse:: parse_crate_from_file ( krate, & sess) . ok ( ) . unwrap ( ) ;
918
+ // Convert DiagnosticBuilder -> Error so the `?` works
919
+ let krate = parse:: parse_crate_from_file ( krate, & sess) . map_err ( |mut d| {
920
+ // Emit the diagnostic to properly handle it and show error to the user
921
+ d. emit ( ) ;
922
+ anyhow ! ( "failed to parse crate: {:?}" , d)
923
+ } ) ?;
893
924
894
925
// Remove things like functions, impls, traits, etc, that we're not
895
926
// looking at
0 commit comments