...
1 package gmeasure
2
3 import (
4 "fmt"
5 "sort"
6
7 "github.com/onsi/gomega/gmeasure/table"
8 )
9
10
13 type RankingCriteria uint
14
15 const (
16 LowerMeanIsBetter RankingCriteria = iota
17 HigherMeanIsBetter
18 LowerMedianIsBetter
19 HigherMedianIsBetter
20 LowerMinIsBetter
21 HigherMinIsBetter
22 LowerMaxIsBetter
23 HigherMaxIsBetter
24 )
25
26 var rcEnumSupport = newEnumSupport(map[uint]string{uint(LowerMeanIsBetter): "Lower Mean is Better", uint(HigherMeanIsBetter): "Higher Mean is Better", uint(LowerMedianIsBetter): "Lower Median is Better", uint(HigherMedianIsBetter): "Higher Median is Better", uint(LowerMinIsBetter): "Lower Mins is Better", uint(HigherMinIsBetter): "Higher Min is Better", uint(LowerMaxIsBetter): "Lower Max is Better", uint(HigherMaxIsBetter): "Higher Max is Better"})
27
28 func (s RankingCriteria) String() string { return rcEnumSupport.String(uint(s)) }
29 func (s *RankingCriteria) UnmarshalJSON(b []byte) error {
30 out, err := rcEnumSupport.UnmarshJSON(b)
31 *s = RankingCriteria(out)
32 return err
33 }
34 func (s RankingCriteria) MarshalJSON() ([]byte, error) { return rcEnumSupport.MarshJSON(uint(s)) }
35
36
41 type Ranking struct {
42 Criteria RankingCriteria
43 Stats []Stats
44 }
45
46
49 func RankStats(criteria RankingCriteria, stats ...Stats) Ranking {
50 sort.Slice(stats, func(i int, j int) bool {
51 switch criteria {
52 case LowerMeanIsBetter:
53 return stats[i].FloatFor(StatMean) < stats[j].FloatFor(StatMean)
54 case HigherMeanIsBetter:
55 return stats[i].FloatFor(StatMean) > stats[j].FloatFor(StatMean)
56 case LowerMedianIsBetter:
57 return stats[i].FloatFor(StatMedian) < stats[j].FloatFor(StatMedian)
58 case HigherMedianIsBetter:
59 return stats[i].FloatFor(StatMedian) > stats[j].FloatFor(StatMedian)
60 case LowerMinIsBetter:
61 return stats[i].FloatFor(StatMin) < stats[j].FloatFor(StatMin)
62 case HigherMinIsBetter:
63 return stats[i].FloatFor(StatMin) > stats[j].FloatFor(StatMin)
64 case LowerMaxIsBetter:
65 return stats[i].FloatFor(StatMax) < stats[j].FloatFor(StatMax)
66 case HigherMaxIsBetter:
67 return stats[i].FloatFor(StatMax) > stats[j].FloatFor(StatMax)
68 }
69 return false
70 })
71
72 out := Ranking{
73 Criteria: criteria,
74 Stats: stats,
75 }
76
77 return out
78 }
79
80
83 func (c Ranking) Winner() Stats {
84 if len(c.Stats) == 0 {
85 return Stats{}
86 }
87 return c.Stats[0]
88 }
89
90 func (c Ranking) report(enableStyling bool) string {
91 if len(c.Stats) == 0 {
92 return "Empty Ranking"
93 }
94 t := table.NewTable()
95 t.TableStyle.EnableTextStyling = enableStyling
96 t.AppendRow(table.R(
97 table.C("Experiment"), table.C("Name"), table.C("N"), table.C("Min"), table.C("Median"), table.C("Mean"), table.C("StdDev"), table.C("Max"),
98 table.Divider("="),
99 "{{bold}}",
100 ))
101
102 for idx, stats := range c.Stats {
103 name := stats.MeasurementName
104 if stats.Units != "" {
105 name = name + " [" + stats.Units + "]"
106 }
107 experimentName := stats.ExperimentName
108 style := stats.Style
109 if idx == 0 {
110 style = "{{bold}}" + style
111 name += "\n*Winner*"
112 experimentName += "\n*Winner*"
113 }
114 r := table.R(style)
115 t.AppendRow(r)
116 r.AppendCell(table.C(experimentName), table.C(name))
117 r.AppendCell(stats.cells()...)
118
119 }
120 out := fmt.Sprintf("Ranking Criteria: %s\n", c.Criteria)
121 if enableStyling {
122 out = "{{bold}}" + out + "{{/}}"
123 }
124 out += t.Render()
125 return out
126 }
127
128
132 func (c Ranking) ColorableString() string {
133 return c.report(true)
134 }
135
136
139 func (c Ranking) String() string {
140 return c.report(false)
141 }
142
View as plain text