1package numfmt23import (4 "testing"56 "src.rest/cat/012/internal/locale"7)89func TestFormat(t *testing.T) {10 tests := []struct {11 v float6412 pat string13 want string14 }{15 {1234.5, "#,##0.00", "1,234.50"},16 {-1234.5, "#,##0.00", "-1,234.50"},17 {0.5, "#,##0", "1"},18 {0, "#,##0.00", "0.00"},19 {1234567.891, "#,##0", "1,234,568"},20 {1.005, "0.00", "1.01"}, // 15 significant digits, not binary21 {2.5, "0", "3"},22 {-2.5, "0", "-3"},23 {-0.001, "0.00", "0.00"}, // no negative zero24 {0.1234, "0%", "12%"},25 {0.1234, "0.00%", "12.34%"},26 {1234.5, "0.00E+00", "1.23E+03"},27 {0.000123, "0.00E+00", "1.23E-04"},28 {9.999, "0.00E+00", "1.00E+01"},29 {0, "0.00E+00", "0.00E+00"},30 {1234.5, `"$"#,##0.00`, "$1,234.50"},31 {-1234.5, `"$"#,##0.00`, "-$1,234.50"},32 {-1234.5, "#,##0.00;(#,##0.00)", "(1,234.50)"},33 {0, "#,##0;(#,##0);\"zero\"", "zero"},34 {1.5, "0.0#", "1.5"},35 {1.25, "0.0#", "1.25"},36 {1.5, "0.??", "1.5 "},37 {5, "000", "005"},38 {12345, "#,##0,", "12"},39 {1234.5, "#,##0.00 \"kg\"", "1,234.50 kg"},40 {0.5, "#.##", ".5"},41 {12.5, "General", "12.5"},42 {5551234, "000-0000", "555-1234"},43 {1.5, "General.00", "1.5.00"}, // placeholders after General get zeros44 // Fractions, as Sheets shows them.45 {0.75, "# ?/?", "3/4"},46 {1.75, "# ?/?", "1 3/4"},47 {-1.75, "# ?/?", "-1 3/4"},48 {0.75, "0 ?/?", "0 3/4"},49 {2, "# ?/?", "2"},50 {0, "# ?/?", "0"},51 {1.99, "# ?/?", "2"},52 {0.3333, "# ?/?", "1/3"},53 {3.14159, "# ??/??", "3 14/99"},54 {1.5, "# ??/??", "1 1/2 "},55 {0.1234, "# ??/??", "10/81"},56 {1.3, "# ?/4", "1 1/4"},57 {0.5, "# ?/8", "4/8"},58 {0.37, "# ??/100", "37/100"},59 {1.75, "?/?", "7/4"},60 {1.5, `# ?/? "cups"`, "1 1/2 cups"},61 {1234.5, "#,##0 ?/?", "1,234 1/2"},62 // Dates and times: 46291 is 2026-09-26, a Saturday.63 {46291, "m/d/yyyy", "9/26/2026"},64 {46291, "yyyy-mm-dd", "2026-09-26"},65 {46291, "mmm d, yyyy", "Sep 26, 2026"},66 {46291, "dddd, mmmm d", "Saturday, September 26"},67 {46291, "ddd mmmmm yy", "Sat S 26"},68 {46291.6041666667, "h:mm am/pm", "2:30 PM"},69 {46291.6041666667, "hh:mm:ss", "14:30:00"},70 {0.5, "h:mm:ss AM/PM", "12:00:00 PM"},71 {0, "h:mm a/p", "12:00 A"},72 {1.0423611111, "[h]:mm:ss", "25:01:00"},73 {-0.5, "[h]:mm", "-12:00"},74 {0.000011574, "h:mm:ss.00", "0:00:01.00"},75 {0.0000173611, "mm:ss.0", "00:01.5"},76 {46291.99999999, "m/d/yyyy h:mm", "9/27/2026 0:00"},77 {0, "m/d/yyyy", "12/30/1899"},78 {-1, "yyyy-mm-dd", "1899-12-29"},79 {61, "yyyy-mm-dd", "1900-03-01"},80 {2958465, "yyyy-mm-dd", "9999-12-31"},81 }82 for _, tt := range tests {83 if got := Format(tt.v, tt.pat); got != tt.want {84 t.Errorf("Format(%v, %q) = %q, want %q", tt.v, tt.pat, got, tt.want)85 }86 }87}8889func TestAdjustDecimals(t *testing.T) {90 for _, tt := range []struct{ pat, want string }{91 {"0.00", "0.000"}, {"#,##0", "#,##0.0"}, {`"$"#,##0.00_);("$"#,##0.00)`, `"$"#,##0.000_);("$"#,##0.000)`},92 {"0.00E+00", "0.000E+00"}, {"0%", "0.0%"},93 } {94 if got := AdjustDecimals(tt.pat, 1); got != tt.want {95 t.Errorf("AdjustDecimals(%q, 1) = %q, want %q", tt.pat, got, tt.want)96 }97 }98 if got := AdjustDecimals("0.0", -1); got != "0" {99 t.Errorf("AdjustDecimals(0.0, -1) = %q", got)100 }101}102103// TestFormatNames checks month and day names follow the locale's104// language, in the form a date with a day takes where the language has105// one, and its words for AM and PM.106func TestFormatNames(t *testing.T) {107 const sat = 46291.6041666667 // 2026-09-26 14:30, a Saturday108 for _, tt := range []struct{ tag, pat, want string }{109 {"de-DE", "dddd, d. mmmm yyyy", "Samstag, 26. September 2026"},110 {"de-DE", "ddd d mmm", "Sa 26 Sep"},111 {"fr-FR", "dddd d mmmm", "samedi 26 septembre"},112 {"fr-FR", "d mmm yy", "26 sept. 26"},113 {"pl-PL", "d mmmm yyyy", "26 września 2026"},114 {"pl-PL", "mmmm yyyy", "wrzesień 2026"},115 {"ru-RU", "mmmmm", "С"},116 {"ja-JP", "h:mm AM/PM", "2:30 午後"},117 {"zh-CN", "dddd", "星期六"},118 {"en-GB", "ddd d mmm", "Sat 26 Sep"},119 {"de-DE", "h:mm AM/PM", "2:30 PM"},120 } {121 l, _ := locale.Lookup(tt.tag)122 if got := FormatIn(sat, tt.pat, l); got != tt.want {123 t.Errorf("%s FormatIn(%q) = %q, want %q", tt.tag, tt.pat, got, tt.want)124 }125 }126}127128// TestFormatLCID checks a [$-407] tag shows its locale's names, as in129// Excel, whatever the locale shown in.130func TestFormatLCID(t *testing.T) {131 for _, tt := range []struct{ pat, want string }{132 {"[$-407]d. mmmm yyyy", "26. September 2026"},133 {"[$-40C]dddd", "samedi"},134 {"[$-10407]mmm", "Sep"},135 {"[$€-407]mmmm", "€September"},136 {"[$-F800]dddd", "Saturday"},137 } {138 if got := Format(46291, tt.pat); got != tt.want {139 t.Errorf("Format(%q) = %q, want %q", tt.pat, got, tt.want)140 }141 }142}143144func TestRound(t *testing.T) {145 tests := []struct {146 x float64147 places int148 mode Rounding149 want float64150 }{151 {1.005, 2, HalfUp, 1.01},152 {2.675, 2, HalfUp, 2.68},153 {-2.5, 0, HalfUp, -3},154 {1234.5, -2, HalfUp, 1200},155 {-1.005, 2, HalfUp, -1.01},156 {1.5, 14, HalfUp, 1.5}, // exact inputs stay exact157 {0.1 + 0.2, 15, HalfUp, 0.3},158 {1.23456789012345, 14, HalfUp, 1.23456789012345}, // Sheets says ...346159 {1.23456789012345, 15, HalfUp, 1.23456789012345},160 {2.301, 1, Up, 2.4},161 {-2.39, 1, Down, -2.3},162 }163 for _, tt := range tests {164 if got := Round(tt.x, tt.places, tt.mode); got != tt.want {165 t.Errorf("Round(%v, %d, %v) = %v, want %v", tt.x, tt.places, tt.mode, got, tt.want)166 }167 }168}169170func TestEntered(t *testing.T) {171 for in, want := range map[string]string{172 "123456789012345678": "123456789012345000",173 "123456789012345": "123456789012345",174 "0.00012345678901234567": "0.00012345678901234500",175 "1.2345678901234567e10": "1.2345678901234500e10",176 "12.5": "12.5",177 } {178 if got := Entered(in); got != want {179 t.Errorf("Entered(%s) = %s, want %s", in, got, want)180 }181 }182}