Repository: RustPython/RustPython (language: rust)

Issue:
Format panic in test_int__format__locale
## Issues

In `Lib/test/test_types.py``test_int__format__locale`, if you change from `format(x, 'n')` to `format(x, ',')` and run the test, RustPython will panic! It doesn't crash in CPython!

See #4593 for test case

broken test case of FormatSpec::format_int
test case of #4588
Format panic in test_int__format__locale
## Issues

In `Lib/test/test_types.py``test_int__format__locale`, if you change from `format(x, 'n')` to `format(x, ',')` and run the test, RustPython will panic! It doesn't crash in CPython!

See #4593 for test case



Discussion / hints:
not reproducible

not reproducible

Fix patch:
diff --git a/common/src/format.rs b/common/src/format.rs
index ca994c6dbe..62c703c85f 100644
--- a/common/src/format.rs
+++ b/common/src/format.rs
@@ -335,10 +335,11 @@ impl FormatSpec {
         let offset = (disp_digit_cnt % (inter + 1) == 0) as i32;
         let disp_digit_cnt = disp_digit_cnt + offset;
         let pad_cnt = disp_digit_cnt - magnitude_len;
-        if pad_cnt > 0 {
+        let sep_cnt = disp_digit_cnt / (inter + 1);
+        let diff = pad_cnt - sep_cnt;
+        if pad_cnt > 0 && diff > 0 {
             // separate with 0 padding
-            let sep_cnt = disp_digit_cnt / (inter + 1);
-            let padding = "0".repeat((pad_cnt - sep_cnt) as usize);
+            let padding = "0".repeat(diff as usize);
             let padded_num = format!("{padding}{magnitude_str}");
             FormatSpec::insert_separator(padded_num, inter, sep, sep_cnt)
         } else {
@@ -1027,6 +1028,16 @@ mod tests {
         );
     }
 
+    #[test]
+    fn test_format_int_sep() {
+        let spec = FormatSpec::parse(",").expect("");
+        assert_eq!(spec.grouping_option, Some(FormatGrouping::Comma));
+        assert_eq!(
+            spec.format_int(&BigInt::from_str("1234567890123456789012345678").unwrap()),
+            Ok("1,234,567,890,123,456,789,012,345,678".to_owned())
+        );
+    }
+
     #[test]
     fn test_format_parse() {
         let expected = Ok(FormatString {


Test patch:
diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py
index 41ab27f37b..56dc71fb73 100644
--- a/Lib/test/test_types.py
+++ b/Lib/test/test_types.py
@@ -403,7 +403,6 @@ def test_float__format__locale(self):
             self.assertEqual(locale.format_string('%g', x, grouping=True), format(x, 'n'))
             self.assertEqual(locale.format_string('%.10g', x, grouping=True), format(x, '.10n'))
 
-    @unittest.skip("TODO: RustPython format code n is not integrated with locale")
     @run_with_locale('LC_NUMERIC', 'en_US.UTF8')
     def test_int__format__locale(self):
         # test locale support for __format__ code 'n' for integers
@@ -422,6 +421,9 @@ def test_int__format__locale(self):
             self.assertEqual(len(format(0, rfmt)), len(format(x, rfmt)))
             self.assertEqual(len(format(0, lfmt)), len(format(x, lfmt)))
             self.assertEqual(len(format(0, cfmt)), len(format(x, cfmt)))
+    
+    if sys.platform != "darwin":
+        test_int__format__locale = unittest.expectedFailure(test_int__format__locale)
 
     def test_float__format__(self):
         def test(f, format_spec, result):
diff --git a/extra_tests/snippets/builtin_format.py b/extra_tests/snippets/builtin_format.py
index b261ce154f..6a8e6077ee 100644
--- a/extra_tests/snippets/builtin_format.py
+++ b/extra_tests/snippets/builtin_format.py
@@ -133,3 +133,9 @@ def test_zero_padding():
 assert f"{3.1415:#.2}" == "3.1"
 assert f"{3.1415:#.3}" == "3.14"
 assert f"{3.1415:#.4}" == "3.142"
+
+# test issue 4558
+x = 123456789012345678901234567890
+for i in range(0, 30):
+    format(x, ',')
+    x = x // 10