github.com/onsi/ginkgo@v1.16.6-0.20211118180735-4e1925ba4c95/internal/report_entry_test.go (about) 1 package internal_test 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "time" 7 8 . "github.com/onsi/ginkgo" 9 "github.com/onsi/ginkgo/internal" 10 "github.com/onsi/ginkgo/types" 11 . "github.com/onsi/gomega" 12 ) 13 14 type SomeStruct struct { 15 Label string 16 Count int 17 } 18 19 type StringerStruct struct { 20 Label string 21 Count int 22 } 23 24 func (s StringerStruct) String() string { 25 return fmt.Sprintf("%s %d", s.Label, s.Count) 26 } 27 28 type ColorableStringerStruct struct { 29 Label string 30 Count int 31 } 32 33 func (s ColorableStringerStruct) String() string { 34 return fmt.Sprintf("%s %d", s.Label, s.Count) 35 } 36 37 func (s ColorableStringerStruct) ColorableString() string { 38 return fmt.Sprintf("{{red}}%s {{green}}%d{{/}}", s.Label, s.Count) 39 } 40 41 func reportEntryJSONRoundTrip(reportEntry internal.ReportEntry) internal.ReportEntry { 42 data, err := json.Marshal(reportEntry) 43 ExpectWithOffset(1, err).ShouldNot(HaveOccurred()) 44 var out internal.ReportEntry 45 ExpectWithOffset(1, json.Unmarshal(data, &out)).Should(Succeed()) 46 return out 47 } 48 49 var _ = Describe("ReportEntry and ReportEntries", func() { 50 var reportEntry internal.ReportEntry 51 var err error 52 53 Describe("ReportEntry with no passed-in value", func() { 54 BeforeEach(func() { 55 reportEntry, err = internal.NewReportEntry("name", cl) 56 Ω(err).ShouldNot(HaveOccurred()) 57 }) 58 59 It("returns a correctly configured ReportEntry", func() { 60 Ω(reportEntry.Visibility).Should(Equal(types.ReportEntryVisibilityAlways)) 61 Ω(reportEntry.Name).Should(Equal("name")) 62 Ω(reportEntry.Time).Should(BeTemporally("~", time.Now(), time.Second)) 63 Ω(reportEntry.Location).Should(Equal(cl)) 64 Ω(reportEntry.GetRawValue()).Should(BeNil()) 65 }) 66 67 It("has an empty StringRepresentation", func() { 68 Ω(reportEntry.StringRepresentation()).Should(BeZero()) 69 }) 70 71 It("round-trips through JSON correctly", func() { 72 rtEntry := reportEntryJSONRoundTrip(reportEntry) 73 Ω(rtEntry.Visibility).Should(Equal(types.ReportEntryVisibilityAlways)) 74 Ω(rtEntry.Name).Should(Equal("name")) 75 Ω(rtEntry.Time).Should(BeTemporally("~", time.Now(), time.Second)) 76 Ω(rtEntry.Location).Should(Equal(cl)) 77 Ω(rtEntry.GetRawValue()).Should(BeNil()) 78 Ω(rtEntry.StringRepresentation()).Should(BeZero()) 79 }) 80 }) 81 82 Context("with a string passed-in value", func() { 83 BeforeEach(func() { 84 reportEntry, err = internal.NewReportEntry("name", cl, "bob") 85 Ω(err).ShouldNot(HaveOccurred()) 86 }) 87 88 It("returns a correctly configured ReportEntry", func() { 89 Ω(reportEntry.GetRawValue()).Should(Equal("bob")) 90 }) 91 92 It("has the correct StringRepresentation", func() { 93 Ω(reportEntry.StringRepresentation()).Should(Equal("bob")) 94 }) 95 96 It("round-trips through JSON correctly", func() { 97 rtEntry := reportEntryJSONRoundTrip(reportEntry) 98 Ω(rtEntry.GetRawValue()).Should(Equal("bob")) 99 Ω(rtEntry.StringRepresentation()).Should(Equal("bob")) 100 }) 101 }) 102 103 Context("with a numerical passed-in value", func() { 104 BeforeEach(func() { 105 reportEntry, err = internal.NewReportEntry("name", cl, 17) 106 Ω(err).ShouldNot(HaveOccurred()) 107 }) 108 109 It("returns a correctly configured ReportEntry", func() { 110 Ω(reportEntry.GetRawValue()).Should(Equal(17)) 111 }) 112 113 It("has the correct StringRepresentation", func() { 114 Ω(reportEntry.StringRepresentation()).Should(Equal("17")) 115 }) 116 117 It("round-trips through JSON correctly", func() { 118 rtEntry := reportEntryJSONRoundTrip(reportEntry) 119 Ω(rtEntry.GetRawValue()).Should(Equal(float64(17))) 120 Ω(rtEntry.StringRepresentation()).Should(Equal("17")) 121 }) 122 }) 123 124 Context("with a struct passed-in value", func() { 125 BeforeEach(func() { 126 reportEntry, err = internal.NewReportEntry("name", cl, SomeStruct{"bob", 17}) 127 Ω(err).ShouldNot(HaveOccurred()) 128 }) 129 130 It("returns a correctly configured ReportEntry", func() { 131 Ω(reportEntry.GetRawValue()).Should(Equal(SomeStruct{"bob", 17})) 132 }) 133 134 It("has the correct StringRepresentation", func() { 135 Ω(reportEntry.StringRepresentation()).Should(Equal("{Label:bob Count:17}")) 136 }) 137 138 It("round-trips through JSON correctly", func() { 139 rtEntry := reportEntryJSONRoundTrip(reportEntry) 140 Ω(rtEntry.GetRawValue()).Should(Equal(map[string]interface{}{"Label": "bob", "Count": float64(17)})) 141 Ω(rtEntry.StringRepresentation()).Should(Equal("{Label:bob Count:17}")) 142 }) 143 144 It("can be rehydrated into the correct struct, manually", func() { 145 rtEntry := reportEntryJSONRoundTrip(reportEntry) 146 var s SomeStruct 147 Ω(json.Unmarshal([]byte(rtEntry.Value.AsJSON), &s)).Should(Succeed()) 148 Ω(s).Should(Equal(SomeStruct{"bob", 17})) 149 }) 150 }) 151 152 Context("with a stringer passed-in value", func() { 153 BeforeEach(func() { 154 reportEntry, err = internal.NewReportEntry("name", cl, StringerStruct{"bob", 17}) 155 Ω(err).ShouldNot(HaveOccurred()) 156 }) 157 158 It("returns a correctly configured ReportEntry", func() { 159 Ω(reportEntry.GetRawValue()).Should(Equal(StringerStruct{"bob", 17})) 160 }) 161 162 It("has the correct StringRepresentation", func() { 163 Ω(reportEntry.StringRepresentation()).Should(Equal("bob 17")) 164 }) 165 166 It("round-trips through JSON correctly", func() { 167 rtEntry := reportEntryJSONRoundTrip(reportEntry) 168 Ω(rtEntry.GetRawValue()).Should(Equal(map[string]interface{}{"Label": "bob", "Count": float64(17)})) 169 Ω(rtEntry.StringRepresentation()).Should(Equal("bob 17")) 170 }) 171 }) 172 173 Context("with a ColorableStringer passed-in value", func() { 174 BeforeEach(func() { 175 reportEntry, err = internal.NewReportEntry("name", cl, ColorableStringerStruct{"bob", 17}) 176 Ω(err).ShouldNot(HaveOccurred()) 177 }) 178 179 It("returns a correctly configured ReportEntry", func() { 180 Ω(reportEntry.GetRawValue()).Should(Equal(ColorableStringerStruct{"bob", 17})) 181 }) 182 183 It("has the correct StringRepresentation", func() { 184 Ω(reportEntry.StringRepresentation()).Should(Equal("{{red}}bob {{green}}17{{/}}")) 185 }) 186 187 It("round-trips through JSON correctly", func() { 188 rtEntry := reportEntryJSONRoundTrip(reportEntry) 189 Ω(rtEntry.GetRawValue()).Should(Equal(map[string]interface{}{"Label": "bob", "Count": float64(17)})) 190 Ω(rtEntry.StringRepresentation()).Should(Equal("{{red}}bob {{green}}17{{/}}")) 191 }) 192 }) 193 194 Context("with multiple passed-in values", func() { 195 It("errors", func() { 196 reportEntry, err = internal.NewReportEntry("name", cl, 1, "2") 197 Ω(err).Should(MatchError(types.GinkgoErrors.TooManyReportEntryValues(cl, "2"))) 198 }) 199 }) 200 201 Context("with the Offset decoration", func() { 202 It("computes a new offset code location", func() { 203 reportEntry, err = internal.NewReportEntry("name", cl, Offset(1)) 204 Ω(reportEntry.GetRawValue()).Should(BeNil()) 205 expectedCL := types.NewCodeLocation(2) // NewReportEntry has a BaseOffset of 2 206 Ω(reportEntry.Location.FileName).Should(Equal(expectedCL.FileName)) 207 }) 208 }) 209 Context("with a CodeLocation", func() { 210 It("uses the passed-in codelocation", func() { 211 customCl := types.NewCustomCodeLocation("foo") 212 reportEntry, err = internal.NewReportEntry("name", cl, customCl) 213 Ω(reportEntry.GetRawValue()).Should(BeNil()) 214 Ω(reportEntry.Location).Should(Equal(customCl)) 215 }) 216 }) 217 Context("with a ReportEntryVisibility", func() { 218 It("uses the passed in visibility", func() { 219 reportEntry, err = internal.NewReportEntry("name", cl, types.ReportEntryVisibilityFailureOrVerbose) 220 Ω(reportEntry.GetRawValue()).Should(BeNil()) 221 Ω(reportEntry.Visibility).Should(Equal(types.ReportEntryVisibilityFailureOrVerbose)) 222 }) 223 }) 224 Context("with a time", func() { 225 It("uses the passed in time", func() { 226 t := time.Date(1984, 3, 7, 0, 0, 0, 0, time.Local) 227 reportEntry, err = internal.NewReportEntry("name", cl, t) 228 Ω(reportEntry.GetRawValue()).Should(BeNil()) 229 Ω(reportEntry.Time).Should(Equal(t)) 230 }) 231 }) 232 233 Describe("ReportEntries.HasVisibility", func() { 234 It("is true when the ReportEntries have the requested visibilities", func() { 235 entries := types.ReportEntries{ 236 types.ReportEntry{Visibility: types.ReportEntryVisibilityAlways}, 237 types.ReportEntry{Visibility: types.ReportEntryVisibilityAlways}, 238 } 239 240 Ω(entries.HasVisibility(types.ReportEntryVisibilityNever, types.ReportEntryVisibilityAlways)).Should(BeTrue()) 241 Ω(entries.HasVisibility(types.ReportEntryVisibilityNever, types.ReportEntryVisibilityFailureOrVerbose)).Should(BeFalse()) 242 }) 243 }) 244 245 Describe("ReportEntries.WithVisibility", func() { 246 It("returns the subset of report entries with the requested visibilities", func() { 247 entries := types.ReportEntries{ 248 types.ReportEntry{Name: "A", Visibility: types.ReportEntryVisibilityAlways}, 249 types.ReportEntry{Name: "B", Visibility: types.ReportEntryVisibilityFailureOrVerbose}, 250 types.ReportEntry{Name: "C", Visibility: types.ReportEntryVisibilityNever}, 251 } 252 Ω(entries.WithVisibility(types.ReportEntryVisibilityAlways, types.ReportEntryVisibilityFailureOrVerbose)).Should(Equal( 253 types.ReportEntries{ 254 types.ReportEntry{Name: "A", Visibility: types.ReportEntryVisibilityAlways}, 255 types.ReportEntry{Name: "B", Visibility: types.ReportEntryVisibilityFailureOrVerbose}, 256 }, 257 )) 258 259 }) 260 }) 261 262 Describe("mini-integration test - validating that the DSL correctly wires into the suite", func() { 263 Context("when passed a value", func() { 264 It("works!", func() { 265 AddReportEntry("A Test ReportEntry", ColorableStringerStruct{"bob", 17}, types.ReportEntryVisibilityFailureOrVerbose) 266 }) 267 268 ReportAfterEach(func(report SpecReport) { 269 if report.State.Is(types.SpecStatePassed) { 270 Ω(report.ReportEntries[0].StringRepresentation()).Should(Equal("{{red}}bob {{green}}17{{/}}")) 271 } 272 }) 273 }) 274 275 Context("when passed a pointer that subsequently changes", func() { 276 var obj *ColorableStringerStruct 277 278 BeforeEach(func() { 279 obj = &ColorableStringerStruct{"bob", 17} 280 }) 281 282 It("works!", func() { 283 AddReportEntry("A Test ReportEntry", obj, types.ReportEntryVisibilityFailureOrVerbose) 284 }) 285 286 AfterEach(func() { 287 obj.Label = "alice" 288 obj.Count = 42 289 }) 290 291 ReportAfterEach(func(report SpecReport) { 292 if report.State.Is(types.SpecStatePassed) { 293 Ω(report.ReportEntries[0].StringRepresentation()).Should(Equal("{{red}}alice {{green}}42{{/}}")) 294 } 295 }) 296 }) 297 }) 298 })