// MIT License // Copyright (c) 2022 Tree Xie // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. package charts import ( "strconv" "testing" "github.com/stretchr/testify/assert" ) func TestPieChart(t *testing.T) { assert := assert.New(t) tests := []struct { render func(*Painter) ([]byte, error) result string }{ { render: func(p *Painter) ([]byte, error) { values := []float64{ 1048, 735, 580, 484, 300, } _, err := NewPieChart(p, PieChartOption{ SeriesList: NewPieSeriesList(values, PieSeriesOption{ Label: SeriesLabel{ Show: true, }, }), Title: TitleOption{ Text: "Rainfall vs Evaporation", Subtext: "Fake Data", Left: PositionCenter, }, Padding: Box{ Top: 20, Right: 20, Bottom: 20, Left: 20, }, Legend: LegendOption{ Orient: OrientVertical, Data: []string{ "Search Engine", "Direct", "Email", "Union Ads", "Video Ads", }, Left: PositionLeft, }, }).Render() if err != nil { return nil, err } return p.Bytes() }, result: "\\nSearch EngineDirectEmailUnion AdsVideo AdsRainfall vs EvaporationFake DataSearch Engine: 33.3%Direct: 23.35%Email: 18.43%Union Ads: 15.37%Video Ads: 9.53%", }, } for _, tt := range tests { p, err := NewPainter(PainterOptions{ Type: ChartOutputSVG, Width: 600, Height: 400, }, PainterThemeOption(defaultTheme)) assert.Nil(err) data, err := tt.render(p.Child(PainterPaddingOption(Box{ Left: 20, Top: 20, Right: 20, Bottom: 20, }))) assert.Nil(err) assert.Equal(tt.result, string(data)) } } func TestPieChartWithLabelsValuesSortedDescending(t *testing.T) { assert := assert.New(t) tests := []struct { render func(*Painter) ([]byte, error) result string }{ { render: func(p *Painter) ([]byte, error) { values := []float64{ 84358845, 68070697, 58850717, 48059777, 36753736, 19051562, 17947406, 11754004, 10827529, 10521556, 10467366, 10394055, 9597085, 9104772, 6447710, 5932654, 5563970, 5428792, 5194336, 3850894, 2857279, 2116792, 1883008, 1373101, 920701, 660809, 542051, } _, err := NewPieChart(p, PieChartOption{ SeriesList: NewPieSeriesList(values, PieSeriesOption{ Label: SeriesLabel{ Show: true, Formatter: "{b} ({c} ≅ {d})", }, Radius: "200", }), Title: TitleOption{ Text: "European Union member states by population", Left: PositionRight, }, Padding: Box{ Top: 20, Right: 20, Bottom: 20, Left: 20, }, Legend: LegendOption{ Data: []string{ "Germany", "France", "Italy", "Spain", "Poland", "Romania", "Netherlands", "Belgium", "Czech Republic", "Sweden", "Portugal", "Greece", "Hungary", "Austria", "Bulgaria", "Denmark", "Finland", "Slovakia", "Ireland", "Croatia", "Lithuania", "Slovenia", "Latvia", "Estonia", "Cyprus", "Luxembourg", "Malta", }, Show: FalseFlag(), }, }).Render() if err != nil { return nil, err } return p.Bytes() }, result: "\\nEuropean Union member states by populationGermany (84358845 ≅ 18.8%)France (68070697 ≅ 15.17%)Italy (58850717 ≅ 13.12%)Netherlands (17947406 ≅ 4%)Romania (19051562 ≅ 4.24%)Poland (36753736 ≅ 8.19%)Spain (48059777 ≅ 10.71%)Belgium (11754004 ≅ 2.62%)Czech Republic (10827529 ≅ 2.41%)Sweden (10521556 ≅ 2.34%)Portugal (10467366 ≅ 2.33%)Greece (10394055 ≅ 2.31%)Hungary (9597085 ≅ 2.13%)Austria (9104772 ≅ 2.02%)Bulgaria (6447710 ≅ 1.43%)Denmark (5932654 ≅ 1.32%)Finland (5563970 ≅ 1.24%)Slovakia (5428792 ≅ 1.21%)Ireland (5194336 ≅ 1.15%)Croatia (3850894 ≅ 0.85%)Lithuania (2857279 ≅ 0.63%)Slovenia (2116792 ≅ 0.47%)Latvia (1883008 ≅ 0.41%)Estonia (1373101 ≅ 0.3%)Cyprus (920701 ≅ 0.2%)Luxembourg (660809 ≅ 0.14%)Malta (542051 ≅ 0.12%)", }, } for _, tt := range tests { p, err := NewPainter(PainterOptions{ Type: ChartOutputSVG, Width: 1000, Height: 800, }, PainterThemeOption(defaultTheme)) assert.Nil(err) data, err := tt.render(p.Child(PainterPaddingOption(Box{ Left: 20, Top: 20, Right: 20, Bottom: 20, }))) assert.Nil(err) assert.Equal(tt.result, string(data)) } } func TestPieChartWithLabelsValuesUnsorted(t *testing.T) { assert := assert.New(t) tests := []struct { render func(*Painter) ([]byte, error) result string }{ { render: func(p *Painter) ([]byte, error) { values := []float64{ 9104772, 11754004, 6447710, 3850894, 920701, 10827529, 5932654, 1373101, 5563970, 68070697, 84358845, 10394055, 9597085, 5194336, 58850717, 1883008, 2857279, 660809, 542051, 17947406, 36753736, 10467366, 19051562, 5428792, 2116792, 48059777, 10521556, } _, err := NewPieChart(p, PieChartOption{ SeriesList: NewPieSeriesList(values, PieSeriesOption{ Label: SeriesLabel{ Show: true, Formatter: "{b} ({c} ≅ {d})", }, Radius: "200", }), Title: TitleOption{ Text: "European Union member states by population", Left: PositionRight, }, Padding: Box{ Top: 20, Right: 20, Bottom: 20, Left: 20, }, Legend: LegendOption{ Data: []string{ "Austria", "Belgium", "Bulgaria", "Croatia", "Cyprus", "Czech Republic", "Denmark", "Estonia", "Finland", "France", "Germany", "Greece", "Hungary", "Ireland", "Italy", "Latvia", "Lithuania", "Luxembourg", "Malta", "Netherlands", "Poland", "Portugal", "Romania", "Slovakia", "Slovenia", "Spain", "Sweden", }, Show: FalseFlag(), }, }).Render() if err != nil { return nil, err } return p.Bytes() }, result: "\\nEuropean Union member states by populationFrance (68070697 ≅ 15.17%)Finland (5563970 ≅ 1.24%)Estonia (1373101 ≅ 0.3%)Denmark (5932654 ≅ 1.32%)Czech Republic (10827529 ≅ 2.41%)Cyprus (920701 ≅ 0.2%)Croatia (3850894 ≅ 0.85%)Bulgaria (6447710 ≅ 1.43%)Belgium (11754004 ≅ 2.62%)Austria (9104772 ≅ 2.02%)Germany (84358845 ≅ 18.8%)Greece (10394055 ≅ 2.31%)Hungary (9597085 ≅ 2.13%)Poland (36753736 ≅ 8.19%)Netherlands (17947406 ≅ 4%)Malta (542051 ≅ 0.12%)Luxembourg (660809 ≅ 0.14%)Lithuania (2857279 ≅ 0.63%)Latvia (1883008 ≅ 0.41%)Italy (58850717 ≅ 13.12%)Ireland (5194336 ≅ 1.15%)Portugal (10467366 ≅ 2.33%)Romania (19051562 ≅ 4.24%)Slovakia (5428792 ≅ 1.21%)Slovenia (2116792 ≅ 0.47%)Spain (48059777 ≅ 10.71%)Sweden (10521556 ≅ 2.34%)", }, } for _, tt := range tests { p, err := NewPainter(PainterOptions{ Type: ChartOutputSVG, Width: 1000, Height: 800, }, PainterThemeOption(defaultTheme)) assert.Nil(err) data, err := tt.render(p.Child(PainterPaddingOption(Box{ Left: 20, Top: 20, Right: 20, Bottom: 20, }))) assert.Nil(err) assert.Equal(tt.result, string(data)) } } func TestPieChartWith100Labels(t *testing.T) { assert := assert.New(t) tests := []struct { render func(*Painter) ([]byte, error) result string }{ { render: func(p *Painter) ([]byte, error) { var values []float64 var labels []string for i := 1; i <= 100; i++ { values = append(values, float64(1)) labels = append(labels, "Label "+strconv.Itoa(i)) } _, err := NewPieChart(p, PieChartOption{ SeriesList: NewPieSeriesList(values, PieSeriesOption{ Label: SeriesLabel{ Show: true, }, Radius: "200", }), Title: TitleOption{ Text: "Test with 100 labels", Left: PositionRight, }, Padding: Box{ Top: 20, Right: 20, Bottom: 20, Left: 20, }, Legend: LegendOption{ Data: labels, Show: FalseFlag(), }, }).Render() if err != nil { return nil, err } return p.Bytes() }, result: "\\nTest with 100 labelsLabel 25: 1%Label 24: 1%Label 23: 1%Label 22: 1%Label 21: 1%Label 20: 1%Label 19: 1%Label 18: 1%Label 17: 1%Label 16: 1%Label 15: 1%Label 14: 1%Label 13: 1%Label 12: 1%Label 11: 1%Label 10: 1%Label 9: 1%Label 8: 1%Label 7: 1%Label 6: 1%Label 5: 1%Label 4: 1%Label 3: 1%Label 2: 1%Label 1: 1%Label 26: 1%Label 27: 1%Label 28: 1%Label 29: 1%Label 30: 1%Label 31: 1%Label 32: 1%Label 33: 1%Label 34: 1%Label 35: 1%Label 36: 1%Label 37: 1%Label 38: 1%Label 39: 1%Label 40: 1%Label 41: 1%Label 42: 1%Label 43: 1%Label 44: 1%Label 45: 1%Label 46: 1%Label 47: 1%Label 48: 1%Label 49: 1%Label 50: 1%Label 75: 1%Label 74: 1%Label 73: 1%Label 72: 1%Label 71: 1%Label 70: 1%Label 69: 1%Label 68: 1%Label 67: 1%Label 66: 1%Label 65: 1%Label 64: 1%Label 63: 1%Label 62: 1%Label 61: 1%Label 60: 1%Label 59: 1%Label 58: 1%Label 57: 1%Label 56: 1%Label 55: 1%Label 54: 1%Label 53: 1%Label 52: 1%Label 51: 1%Label 76: 1%Label 77: 1%Label 78: 1%Label 79: 1%Label 80: 1%Label 81: 1%Label 82: 1%Label 83: 1%Label 84: 1%Label 85: 1%Label 86: 1%Label 87: 1%Label 88: 1%Label 89: 1%Label 90: 1%Label 91: 1%Label 92: 1%Label 93: 1%Label 94: 1%Label 95: 1%Label 96: 1%Label 97: 1%Label 98: 1%Label 99: 1%Label 100: 1%", }, } for _, tt := range tests { p, err := NewPainter(PainterOptions{ Type: ChartOutputSVG, Width: 1000, Height: 900, }, PainterThemeOption(defaultTheme)) assert.Nil(err) data, err := tt.render(p.Child(PainterPaddingOption(Box{ Left: 20, Top: 20, Right: 20, Bottom: 20, }))) assert.Nil(err) assert.Equal(tt.result, string(data)) } } func TestPieChartFixLabelPos72586(t *testing.T) { assert := assert.New(t) tests := []struct { render func(*Painter) ([]byte, error) result string }{ { render: func(p *Painter) ([]byte, error) { values := []float64{ 397594, 185596, 149086, 144258, 120194, 117514, 99412, 91135, 87282, 76790, 72586, 58818, 58270, 56306, 55486, 54792, 53746, 51460, 41242, 39476, 37414, 36644, 33784, 32788, 32566, 29608, 29558, 29384, 28166, 26998, 26948, 26054, 25804, 25730, 24438, 23782, 22896, 21404, 428978, } _, err := NewPieChart(p, PieChartOption{ SeriesList: NewPieSeriesList(values, PieSeriesOption{ Label: SeriesLabel{ Show: true, Formatter: "{b} ({c} ≅ {d})", }, Radius: "150", }), Title: TitleOption{ Text: "Fix label K (72586)", Left: PositionRight, }, Padding: Box{ Top: 20, Right: 20, Bottom: 20, Left: 20, }, Legend: LegendOption{ Data: []string{ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "AA", "AB", "AC", "AD", "AE", "AF", "AG", "AH", "AI", "AJ", "AK", "AL", "AM", }, Show: FalseFlag(), }, }).Render() if err != nil { return nil, err } return p.Bytes() }, result: "\\nFix label K (72586)C (149086 ≅ 5.04%)B (185596 ≅ 6.28%)A (397594 ≅ 13.45%)D (144258 ≅ 4.88%)E (120194 ≅ 4.06%)F (117514 ≅ 3.97%)G (99412 ≅ 3.36%)H (91135 ≅ 3.08%)I (87282 ≅ 2.95%)J (76790 ≅ 2.59%)Z (29608 ≅ 1%)Y (32566 ≅ 1.1%)X (32788 ≅ 1.1%)W (33784 ≅ 1.14%)V (36644 ≅ 1.24%)U (37414 ≅ 1.26%)T (39476 ≅ 1.33%)S (41242 ≅ 1.39%)R (51460 ≅ 1.74%)Q (53746 ≅ 1.81%)P (54792 ≅ 1.85%)O (55486 ≅ 1.87%)N (56306 ≅ 1.9%)M (58270 ≅ 1.97%)L (58818 ≅ 1.99%)K (72586 ≅ 2.45%)AA (29558 ≅ 1%)AB (29384 ≅ 0.99%)AC (28166 ≅ 0.95%)AD (26998 ≅ 0.91%)AE (26948 ≅ 0.91%)AF (26054 ≅ 0.88%)AG (25804 ≅ 0.87%)AH (25730 ≅ 0.87%)AI (24438 ≅ 0.82%)AJ (23782 ≅ 0.8%)AK (22896 ≅ 0.77%)AL (21404 ≅ 0.72%)AM (428978 ≅ 14.52%)", }, } for _, tt := range tests { p, err := NewPainter(PainterOptions{ Type: ChartOutputSVG, Width: 1150, Height: 550, }, PainterThemeOption(defaultTheme)) assert.Nil(err) data, err := tt.render(p.Child(PainterPaddingOption(Box{ Left: 20, Top: 20, Right: 20, Bottom: 20, }))) assert.Nil(err) assert.Equal(tt.result, string(data)) } }