@@ -171,6 +171,18 @@ mod tests {
171171 assert ! ( !is_newer( "1.0.0" , "not-a-version" ) ) ;
172172 }
173173
174+ #[ test]
175+ fn test_is_newer_four_component ( ) {
176+ // pandas-stubs style: 3.0.0.260204 is newer than 3.0.0
177+ assert ! ( is_newer( "3.0.0.260204" , "3.0.0" ) ) ;
178+ // and newer than a prior 4-component release
179+ assert ! ( is_newer( "3.0.0.260204" , "3.0.0.250204" ) ) ;
180+ // same 4-component version is not newer
181+ assert ! ( !is_newer( "3.0.0.260204" , "3.0.0.260204" ) ) ;
182+ // older 4-component is not newer than current
183+ assert ! ( !is_newer( "3.0.0.250204" , "3.0.0.260204" ) ) ;
184+ }
185+
174186 #[ test]
175187 fn test_classify_bump_major ( ) {
176188 assert_eq ! ( classify_bump( "1.0.0" , "2.0.0" ) , BumpKind :: Major ) ;
@@ -188,6 +200,61 @@ mod tests {
188200 fn test_classify_bump_patch ( ) {
189201 assert_eq ! ( classify_bump( "1.0.0" , "1.0.1" ) , BumpKind :: Patch ) ;
190202 assert_eq ! ( classify_bump( "7.3.0" , "7.3.1" ) , BumpKind :: Patch ) ;
203+ // 4-component versions (e.g. pandas-stubs 3.0.0 → 3.0.0.260204)
204+ assert_eq ! ( classify_bump( "3.0.0" , "3.0.0.260204" ) , BumpKind :: Patch ) ;
205+ assert_eq ! ( classify_bump( "3.0.0.250204" , "3.0.0.260204" ) , BumpKind :: Patch ) ;
206+ }
207+
208+ #[ tokio:: test]
209+ async fn test_check_dep_four_component_update ( ) {
210+ // pandas-stubs pattern: current >=3.0.0, latest 3.0.0.260204
211+ use wiremock:: matchers:: { method, path} ;
212+ use wiremock:: { Mock , MockServer , ResponseTemplate } ;
213+
214+ let server = MockServer :: start ( ) . await ;
215+ Mock :: given ( method ( "GET" ) )
216+ . and ( path ( "/pypi/pandas-stubs/json" ) )
217+ . respond_with ( ResponseTemplate :: new ( 200 ) . set_body_json ( serde_json:: json!( {
218+ "info" : { "version" : "3.0.0.260204" }
219+ } ) ) )
220+ . mount ( & server)
221+ . await ;
222+
223+ let client = PypiClient :: with_base_url ( & server. uri ( ) ) . unwrap ( ) ;
224+ let dep = crate :: parsers:: Dependency {
225+ name : "pandas-stubs" . to_string ( ) ,
226+ constraint : ">=3.0.0" . to_string ( ) ,
227+ } ;
228+ let update = check_dep ( & client, & dep) . await . unwrap ( ) . unwrap ( ) ;
229+ assert_eq ! ( update. latest, "3.0.0.260204" ) ;
230+ assert_eq ! ( update. bump_kind, BumpKind :: Patch ) ;
231+ assert_eq ! ( update. updated_constraint, ">=3.0.0.260204" ) ;
232+ }
233+
234+ #[ tokio:: test]
235+ async fn test_check_dep_four_component_to_four_component ( ) {
236+ // pandas-stubs: current >=3.0.0.250204, latest 3.0.0.260204
237+ use wiremock:: matchers:: { method, path} ;
238+ use wiremock:: { Mock , MockServer , ResponseTemplate } ;
239+
240+ let server = MockServer :: start ( ) . await ;
241+ Mock :: given ( method ( "GET" ) )
242+ . and ( path ( "/pypi/pandas-stubs/json" ) )
243+ . respond_with ( ResponseTemplate :: new ( 200 ) . set_body_json ( serde_json:: json!( {
244+ "info" : { "version" : "3.0.0.260204" }
245+ } ) ) )
246+ . mount ( & server)
247+ . await ;
248+
249+ let client = PypiClient :: with_base_url ( & server. uri ( ) ) . unwrap ( ) ;
250+ let dep = crate :: parsers:: Dependency {
251+ name : "pandas-stubs" . to_string ( ) ,
252+ constraint : ">=3.0.0.250204" . to_string ( ) ,
253+ } ;
254+ let update = check_dep ( & client, & dep) . await . unwrap ( ) . unwrap ( ) ;
255+ assert_eq ! ( update. latest, "3.0.0.260204" ) ;
256+ assert_eq ! ( update. bump_kind, BumpKind :: Patch ) ;
257+ assert_eq ! ( update. updated_constraint, ">=3.0.0.260204" ) ;
191258 }
192259
193260 // check_dep and find_updates - network paths covered via wiremock.
0 commit comments