@@ -2186,4 +2186,178 @@ mod tests {
21862186 "Bool primary key should not trigger auto_increment validation"
21872187 ) ;
21882188 }
2189+
2190+ // ── find_missing_enum_fill_with tests ──────────────────────────────
2191+
2192+ fn string_enum ( name : & str , values : Vec < & str > ) -> ColumnType {
2193+ ColumnType :: Complex ( ComplexColumnType :: Enum {
2194+ name : name. into ( ) ,
2195+ values : EnumValues :: String ( values. into_iter ( ) . map ( |s| s. to_string ( ) ) . collect ( ) ) ,
2196+ } )
2197+ }
2198+
2199+ #[ test]
2200+ fn find_missing_enum_fill_with_detects_removed_values ( ) {
2201+ let plan = MigrationPlan {
2202+ id : String :: new ( ) ,
2203+ comment : None ,
2204+ created_at : None ,
2205+ version : 2 ,
2206+ actions : vec ! [ MigrationAction :: ModifyColumnType {
2207+ table: "orders" . into( ) ,
2208+ column: "status" . into( ) ,
2209+ new_type: string_enum( "order_status" , vec![ "pending" , "shipped" ] ) ,
2210+ fill_with: None ,
2211+ } ] ,
2212+ } ;
2213+ let baseline = vec ! [ table(
2214+ "orders" ,
2215+ vec![ col( "status" , string_enum( "order_status" , vec![ "pending" , "shipped" , "cancelled" ] ) ) ] ,
2216+ vec![ ] ,
2217+ ) ] ;
2218+
2219+ let missing = find_missing_enum_fill_with ( & plan, & baseline) ;
2220+ assert_eq ! ( missing. len( ) , 1 ) ;
2221+ assert_eq ! ( missing[ 0 ] . table, "orders" ) ;
2222+ assert_eq ! ( missing[ 0 ] . column, "status" ) ;
2223+ assert_eq ! ( missing[ 0 ] . removed_values, vec![ "cancelled" ] ) ;
2224+ assert_eq ! ( missing[ 0 ] . remaining_values, vec![ "pending" , "shipped" ] ) ;
2225+ }
2226+
2227+ #[ test]
2228+ fn find_missing_enum_fill_with_ignores_additions_only ( ) {
2229+ let plan = MigrationPlan {
2230+ id : String :: new ( ) ,
2231+ comment : None ,
2232+ created_at : None ,
2233+ version : 2 ,
2234+ actions : vec ! [ MigrationAction :: ModifyColumnType {
2235+ table: "orders" . into( ) ,
2236+ column: "status" . into( ) ,
2237+ new_type: string_enum( "order_status" , vec![ "pending" , "shipped" , "delivered" ] ) ,
2238+ fill_with: None ,
2239+ } ] ,
2240+ } ;
2241+ let baseline = vec ! [ table(
2242+ "orders" ,
2243+ vec![ col( "status" , string_enum( "order_status" , vec![ "pending" , "shipped" ] ) ) ] ,
2244+ vec![ ] ,
2245+ ) ] ;
2246+
2247+ let missing = find_missing_enum_fill_with ( & plan, & baseline) ;
2248+ assert ! ( missing. is_empty( ) , "Adding values should not trigger fill_with" ) ;
2249+ }
2250+
2251+ #[ test]
2252+ fn find_missing_enum_fill_with_skips_already_covered ( ) {
2253+ let mut fw = std:: collections:: BTreeMap :: new ( ) ;
2254+ fw. insert ( "cancelled" . to_string ( ) , "'pending'" . to_string ( ) ) ;
2255+
2256+ let plan = MigrationPlan {
2257+ id : String :: new ( ) ,
2258+ comment : None ,
2259+ created_at : None ,
2260+ version : 2 ,
2261+ actions : vec ! [ MigrationAction :: ModifyColumnType {
2262+ table: "orders" . into( ) ,
2263+ column: "status" . into( ) ,
2264+ new_type: string_enum( "order_status" , vec![ "pending" , "shipped" ] ) ,
2265+ fill_with: Some ( fw) ,
2266+ } ] ,
2267+ } ;
2268+ let baseline = vec ! [ table(
2269+ "orders" ,
2270+ vec![ col( "status" , string_enum( "order_status" , vec![ "pending" , "shipped" , "cancelled" ] ) ) ] ,
2271+ vec![ ] ,
2272+ ) ] ;
2273+
2274+ let missing = find_missing_enum_fill_with ( & plan, & baseline) ;
2275+ assert ! ( missing. is_empty( ) , "All removed values are covered by fill_with" ) ;
2276+ }
2277+
2278+ #[ test]
2279+ fn find_missing_enum_fill_with_reports_partially_covered ( ) {
2280+ let mut fw = std:: collections:: BTreeMap :: new ( ) ;
2281+ fw. insert ( "cancelled" . to_string ( ) , "'pending'" . to_string ( ) ) ;
2282+
2283+ let plan = MigrationPlan {
2284+ id : String :: new ( ) ,
2285+ comment : None ,
2286+ created_at : None ,
2287+ version : 2 ,
2288+ actions : vec ! [ MigrationAction :: ModifyColumnType {
2289+ table: "orders" . into( ) ,
2290+ column: "status" . into( ) ,
2291+ new_type: string_enum( "order_status" , vec![ "pending" ] ) ,
2292+ fill_with: Some ( fw) ,
2293+ } ] ,
2294+ } ;
2295+ let baseline = vec ! [ table(
2296+ "orders" ,
2297+ vec![ col( "status" , string_enum( "order_status" , vec![ "pending" , "shipped" , "cancelled" ] ) ) ] ,
2298+ vec![ ] ,
2299+ ) ] ;
2300+
2301+ let missing = find_missing_enum_fill_with ( & plan, & baseline) ;
2302+ assert_eq ! ( missing. len( ) , 1 ) ;
2303+ assert_eq ! ( missing[ 0 ] . removed_values, vec![ "shipped" ] , "Only uncovered value should be reported" ) ;
2304+ }
2305+
2306+ #[ test]
2307+ fn find_missing_enum_fill_with_ignores_integer_enums ( ) {
2308+ let old_type = ColumnType :: Complex ( ComplexColumnType :: Enum {
2309+ name : "priority" . into ( ) ,
2310+ values : EnumValues :: Integer ( vec ! [
2311+ NumValue { name: "low" . into( ) , value: 0 } ,
2312+ NumValue { name: "high" . into( ) , value: 1 } ,
2313+ ] ) ,
2314+ } ) ;
2315+ let new_type = ColumnType :: Complex ( ComplexColumnType :: Enum {
2316+ name : "priority" . into ( ) ,
2317+ values : EnumValues :: Integer ( vec ! [
2318+ NumValue { name: "high" . into( ) , value: 1 } ,
2319+ ] ) ,
2320+ } ) ;
2321+
2322+ let plan = MigrationPlan {
2323+ id : String :: new ( ) ,
2324+ comment : None ,
2325+ created_at : None ,
2326+ version : 2 ,
2327+ actions : vec ! [ MigrationAction :: ModifyColumnType {
2328+ table: "tasks" . into( ) ,
2329+ column: "priority" . into( ) ,
2330+ new_type,
2331+ fill_with: None ,
2332+ } ] ,
2333+ } ;
2334+ let baseline = vec ! [ table( "tasks" , vec![ col( "priority" , old_type) ] , vec![ ] ) ] ;
2335+
2336+ let missing = find_missing_enum_fill_with ( & plan, & baseline) ;
2337+ assert ! ( missing. is_empty( ) , "Integer enum changes should not trigger fill_with" ) ;
2338+ }
2339+
2340+ #[ test]
2341+ fn find_missing_enum_fill_with_ignores_non_enum_type_change ( ) {
2342+ let plan = MigrationPlan {
2343+ id : String :: new ( ) ,
2344+ comment : None ,
2345+ created_at : None ,
2346+ version : 2 ,
2347+ actions : vec ! [ MigrationAction :: ModifyColumnType {
2348+ table: "users" . into( ) ,
2349+ column: "age" . into( ) ,
2350+ new_type: ColumnType :: Simple ( SimpleColumnType :: BigInt ) ,
2351+ fill_with: None ,
2352+ } ] ,
2353+ } ;
2354+ let baseline = vec ! [ table(
2355+ "users" ,
2356+ vec![ col( "age" , ColumnType :: Simple ( SimpleColumnType :: Integer ) ) ] ,
2357+ vec![ ] ,
2358+ ) ] ;
2359+
2360+ let missing = find_missing_enum_fill_with ( & plan, & baseline) ;
2361+ assert ! ( missing. is_empty( ) , "Non-enum type changes should not trigger fill_with" ) ;
2362+ }
21892363}
0 commit comments