@@ -47,6 +47,47 @@ pub struct TestOptions {
4747}
4848
4949impl TestOptions {
50+ /// Tries to create a new instance by detecting inline configurations from the project compile
51+ /// output.
52+ pub fn new (
53+ output : & ProjectCompileOutput ,
54+ root : & Path ,
55+ profiles : Vec < String > ,
56+ base_fuzz : FuzzConfig ,
57+ base_invariant : InvariantConfig ,
58+ ) -> Result < Self , InlineConfigError > {
59+ let natspecs: Vec < NatSpec > = NatSpec :: parse ( output, root) ;
60+ let mut inline_invariant = InlineConfig :: < InvariantConfig > :: default ( ) ;
61+ let mut inline_fuzz = InlineConfig :: < FuzzConfig > :: default ( ) ;
62+
63+ for natspec in natspecs {
64+ // Perform general validation
65+ validate_profiles ( & natspec, & profiles) ?;
66+ FuzzConfig :: validate_configs ( & natspec) ?;
67+ InvariantConfig :: validate_configs ( & natspec) ?;
68+
69+ // Apply in-line configurations for the current profile
70+ let configs: Vec < String > = natspec. current_profile_configs ( ) . collect ( ) ;
71+ let c: & str = & natspec. contract ;
72+ let f: & str = & natspec. function ;
73+ let line: String = natspec. debug_context ( ) ;
74+
75+ match base_fuzz. try_merge ( & configs) {
76+ Ok ( Some ( conf) ) => inline_fuzz. insert ( c, f, conf) ,
77+ Ok ( None ) => { /* No inline config found, do nothing */ }
78+ Err ( e) => Err ( InlineConfigError { line : line. clone ( ) , source : e } ) ?,
79+ }
80+
81+ match base_invariant. try_merge ( & configs) {
82+ Ok ( Some ( conf) ) => inline_invariant. insert ( c, f, conf) ,
83+ Ok ( None ) => { /* No inline config found, do nothing */ }
84+ Err ( e) => Err ( InlineConfigError { line : line. clone ( ) , source : e } ) ?,
85+ }
86+ }
87+
88+ Ok ( Self { fuzz : base_fuzz, invariant : base_invariant, inline_fuzz, inline_invariant } )
89+ }
90+
5091 /// Returns a "fuzz" test runner instance. Parameters are used to select tight scoped fuzz
5192 /// configs that apply for a contract-function pair. A fallback configuration is applied
5293 /// if no specific setup is found for a given input.
@@ -127,83 +168,23 @@ impl TestOptions {
127168 }
128169}
129170
130- impl < ' a , P > TryFrom < ( & ' a ProjectCompileOutput , & ' a P , Vec < String > , FuzzConfig , InvariantConfig ) >
131- for TestOptions
132- where
133- P : AsRef < Path > ,
134- {
135- type Error = InlineConfigError ;
136-
137- /// Tries to create an instance of `Self`, detecting inline configurations from the project
138- /// compile output.
139- ///
140- /// Param is a tuple, whose elements are:
141- /// 1. Solidity compiler output, essential to extract natspec test configs.
142- /// 2. Root path to express contract base dirs. This is essential to match inline configs at
143- /// runtime. 3. List of available configuration profiles
144- /// 4. Reference to a fuzz base configuration.
145- /// 5. Reference to an invariant base configuration.
146- fn try_from (
147- value : ( & ' a ProjectCompileOutput , & ' a P , Vec < String > , FuzzConfig , InvariantConfig ) ,
148- ) -> Result < Self , Self :: Error > {
149- let output = value. 0 ;
150- let root = value. 1 ;
151- let profiles = & value. 2 ;
152- let base_fuzz: FuzzConfig = value. 3 ;
153- let base_invariant: InvariantConfig = value. 4 ;
154-
155- let natspecs: Vec < NatSpec > = NatSpec :: parse ( output, root) ;
156- let mut inline_invariant = InlineConfig :: < InvariantConfig > :: default ( ) ;
157- let mut inline_fuzz = InlineConfig :: < FuzzConfig > :: default ( ) ;
158-
159- for natspec in natspecs {
160- // Perform general validation
161- validate_profiles ( & natspec, profiles) ?;
162- FuzzConfig :: validate_configs ( & natspec) ?;
163- InvariantConfig :: validate_configs ( & natspec) ?;
164-
165- // Apply in-line configurations for the current profile
166- let configs: Vec < String > = natspec. current_profile_configs ( ) ;
167- let c: & str = & natspec. contract ;
168- let f: & str = & natspec. function ;
169- let line: String = natspec. debug_context ( ) ;
170-
171- match base_fuzz. try_merge ( & configs) {
172- Ok ( Some ( conf) ) => inline_fuzz. insert ( c, f, conf) ,
173- Err ( e) => Err ( InlineConfigError { line : line. clone ( ) , source : e } ) ?,
174- _ => { /* No inline config found, do nothing */ }
175- }
176-
177- match base_invariant. try_merge ( & configs) {
178- Ok ( Some ( conf) ) => inline_invariant. insert ( c, f, conf) ,
179- Err ( e) => Err ( InlineConfigError { line : line. clone ( ) , source : e } ) ?,
180- _ => { /* No inline config found, do nothing */ }
181- }
182- }
183-
184- Ok ( Self { fuzz : base_fuzz, invariant : base_invariant, inline_fuzz, inline_invariant } )
185- }
186- }
187-
188171/// Builder utility to create a [`TestOptions`] instance.
189172#[ derive( Default ) ]
173+ #[ must_use = "builders do nothing unless you call `build` on them" ]
190174pub struct TestOptionsBuilder {
191175 fuzz : Option < FuzzConfig > ,
192176 invariant : Option < InvariantConfig > ,
193177 profiles : Option < Vec < String > > ,
194- output : Option < ProjectCompileOutput > ,
195178}
196179
197180impl TestOptionsBuilder {
198181 /// Sets a [`FuzzConfig`] to be used as base "fuzz" configuration.
199- #[ must_use = "A base 'fuzz' config must be provided" ]
200182 pub fn fuzz ( mut self , conf : FuzzConfig ) -> Self {
201183 self . fuzz = Some ( conf) ;
202184 self
203185 }
204186
205187 /// Sets a [`InvariantConfig`] to be used as base "invariant" configuration.
206- #[ must_use = "A base 'invariant' config must be provided" ]
207188 pub fn invariant ( mut self , conf : InvariantConfig ) -> Self {
208189 self . invariant = Some ( conf) ;
209190 self
@@ -216,40 +197,21 @@ impl TestOptionsBuilder {
216197 self
217198 }
218199
219- /// Sets a project compiler output instance. This is used to extract
220- /// inline test configurations that override `self.fuzz` and `self.invariant`
221- /// specs when necessary.
222- pub fn compile_output ( mut self , output : & ProjectCompileOutput ) -> Self {
223- self . output = Some ( output. clone ( ) ) ;
224- self
225- }
226-
227200 /// Creates an instance of [`TestOptions`]. This takes care of creating "fuzz" and
228201 /// "invariant" fallbacks, and extracting all inline test configs, if available.
229202 ///
230203 /// `root` is a reference to the user's project root dir. This is essential
231204 /// to determine the base path of generated contract identifiers. This is to provide correct
232205 /// matchers for inline test configs.
233- pub fn build ( self , root : impl AsRef < Path > ) -> Result < TestOptions , InlineConfigError > {
234- let default_profiles = vec ! [ Config :: selected_profile( ) . into( ) ] ;
235- let profiles: Vec < String > = self . profiles . unwrap_or ( default_profiles) ;
206+ pub fn build (
207+ self ,
208+ output : & ProjectCompileOutput ,
209+ root : & Path ,
210+ ) -> Result < TestOptions , InlineConfigError > {
211+ let profiles: Vec < String > =
212+ self . profiles . unwrap_or_else ( || vec ! [ Config :: selected_profile( ) . into( ) ] ) ;
236213 let base_fuzz = self . fuzz . unwrap_or_default ( ) ;
237214 let base_invariant = self . invariant . unwrap_or_default ( ) ;
238-
239- match self . output {
240- Some ( compile_output) => Ok ( TestOptions :: try_from ( (
241- & compile_output,
242- & root,
243- profiles,
244- base_fuzz,
245- base_invariant,
246- ) ) ?) ,
247- None => Ok ( TestOptions {
248- fuzz : base_fuzz,
249- invariant : base_invariant,
250- inline_fuzz : InlineConfig :: default ( ) ,
251- inline_invariant : InlineConfig :: default ( ) ,
252- } ) ,
253- }
215+ TestOptions :: new ( output, & root, profiles, base_fuzz, base_invariant)
254216 }
255217}
0 commit comments