@@ -197,3 +197,50 @@ impl StageConfig {
197197 }
198198 }
199199}
200+
201+ #[ cfg( test) ]
202+ mod tests {
203+ use super :: * ;
204+
205+ /// The plugin persists its chain as `Vec<StageConfig>` JSON in `chain_state`
206+ /// (nih-plug `#[persist]`), and a NAM stage stores its model BY NAME. This is
207+ /// the exact path that recalls a selected model when a DAW project reopens, so
208+ /// guard it: the model name (and the other NAM fields) must survive a JSON
209+ /// round-trip.
210+ #[ test]
211+ fn nam_model_name_survives_chain_state_round_trip ( ) {
212+ let chain = vec ! [
213+ StageConfig :: Nam ( NamConfig {
214+ model_name: Some ( "S-[AMP] Divine Sheep #04" . to_owned( ) ) ,
215+ input_gain_db: 3.0 ,
216+ output_gain_db: -2.0 ,
217+ mix: 0.75 ,
218+ bypassed: true ,
219+ } ) ,
220+ // A passthrough NAM stage (no model) must round-trip as `None`, not "".
221+ StageConfig :: Nam ( NamConfig :: default ( ) ) ,
222+ ] ;
223+
224+ let json = serde_json:: to_string ( & chain) . expect ( "serialize chain_state" ) ;
225+ let restored: Vec < StageConfig > =
226+ serde_json:: from_str ( & json) . expect ( "deserialize chain_state" ) ;
227+
228+ assert_eq ! ( restored. len( ) , 2 ) ;
229+ let StageConfig :: Nam ( cfg) = & restored[ 0 ] else {
230+ panic ! ( "expected a NAM stage at index 0" ) ;
231+ } ;
232+ assert_eq ! ( cfg. model_name. as_deref( ) , Some ( "S-[AMP] Divine Sheep #04" ) ) ;
233+ // Small fixed tolerance — `f32::EPSILON` is the spacing near 1.0, not a
234+ // general-purpose comparison bound.
235+ const TOL : f32 = 1e-6 ;
236+ assert ! ( ( cfg. input_gain_db - 3.0 ) . abs( ) < TOL ) ;
237+ assert ! ( ( cfg. output_gain_db - ( -2.0 ) ) . abs( ) < TOL ) ;
238+ assert ! ( ( cfg. mix - 0.75 ) . abs( ) < TOL ) ;
239+ assert ! ( cfg. bypassed) ;
240+
241+ let StageConfig :: Nam ( cfg) = & restored[ 1 ] else {
242+ panic ! ( "expected a NAM stage at index 1" ) ;
243+ } ;
244+ assert_eq ! ( cfg. model_name, None ) ;
245+ }
246+ }
0 commit comments