github.com/getgauge/gauge@v1.6.9/reporter/coloredConsole.go (about) 1 /*---------------------------------------------------------------- 2 * Copyright (c) ThoughtWorks, Inc. 3 * Licensed under the Apache License, Version 2.0 4 * See LICENSE in the project root for license information. 5 *----------------------------------------------------------------*/ 6 7 package reporter 8 9 import ( 10 "bytes" 11 "fmt" 12 "io" 13 "strings" 14 15 "github.com/apoorvam/goterminal" 16 ct "github.com/daviddengcn/go-colortext" 17 "github.com/getgauge/gauge-proto/go/gauge_messages" 18 "github.com/getgauge/gauge/execution/result" 19 "github.com/getgauge/gauge/gauge" 20 "github.com/getgauge/gauge/logger" 21 ) 22 23 type coloredConsole struct { 24 writer *goterminal.Writer 25 indentation int 26 sceFailuresBuf bytes.Buffer 27 } 28 29 func newColoredConsole(out io.Writer) *coloredConsole { 30 return &coloredConsole{writer: goterminal.New(out)} 31 } 32 33 func (c *coloredConsole) SuiteStart() { 34 } 35 36 func (c *coloredConsole) SpecStart(spec *gauge.Specification, res result.Result) { 37 if res.(*result.SpecResult).Skipped { 38 return 39 } 40 msg := formatSpec(spec.Heading.Value) 41 logger.Info(false, msg) 42 c.displayMessage(msg+newline, ct.Cyan) 43 c.writer.Reset() 44 } 45 46 func (c *coloredConsole) SpecEnd(spec *gauge.Specification, res result.Result) { 47 if res.(*result.SpecResult).Skipped { 48 return 49 } 50 printHookFailureCC(c, res, res.GetPreHook) 51 printHookFailureCC(c, res, res.GetPostHook) 52 c.displayMessage(newline, ct.None) 53 c.writer.Reset() 54 } 55 56 func (c *coloredConsole) ScenarioStart(scenario *gauge.Scenario, i *gauge_messages.ExecutionInfo, res result.Result) { 57 if res.(*result.ScenarioResult).ProtoScenario.ExecutionStatus == gauge_messages.ExecutionStatus_SKIPPED { 58 return 59 } 60 c.indentation += scenarioIndentation 61 msg := formatScenario(scenario.Heading.Value) 62 logger.Info(false, msg) 63 64 indentedText := indent(msg+"\t", c.indentation) 65 c.displayMessage(indentedText, ct.Yellow) 66 } 67 68 func (c *coloredConsole) ScenarioEnd(scenario *gauge.Scenario, res result.Result, i *gauge_messages.ExecutionInfo) { 69 if res.(*result.ScenarioResult).ProtoScenario.ExecutionStatus == gauge_messages.ExecutionStatus_SKIPPED { 70 return 71 } 72 if printHookFailureCC(c, res, res.GetPreHook) { 73 if c.sceFailuresBuf.Len() != 0 { 74 c.displayMessage(newline+strings.Trim(c.sceFailuresBuf.String(), newline)+newline, ct.Red) 75 } else { 76 c.displayMessage(newline, ct.None) 77 } 78 } 79 80 printHookFailureCC(c, res, res.GetPostHook) 81 c.indentation -= scenarioIndentation 82 c.writer.Reset() 83 c.sceFailuresBuf.Reset() 84 } 85 86 func (c *coloredConsole) StepStart(stepText string) { 87 c.indentation += stepIndentation 88 logger.Debug(false, stepText) 89 } 90 91 func (c *coloredConsole) StepEnd(step gauge.Step, res result.Result, execInfo *gauge_messages.ExecutionInfo) { 92 stepRes := res.(*result.StepResult) 93 if !(hookFailed(res.GetPreHook) || hookFailed(res.GetPostHook)) { 94 if stepRes.GetStepFailed() { 95 c.displayMessage(getFailureSymbol(), ct.Red) 96 } else { 97 c.displayMessage(getSuccessSymbol(), ct.Green) 98 } 99 } 100 if printHookFailureCC(c, res, res.GetPreHook) && stepRes.GetStepFailed() { 101 stepText := strings.TrimLeft(prepStepMsg(step.LineText), newline) 102 logger.Error(false, stepText) 103 errMsg := prepErrorMessage(stepRes.ProtoStepExecResult().GetExecutionResult().GetErrorMessage()) 104 logger.Error(false, errMsg) 105 specInfo := prepSpecInfo(execInfo.GetCurrentSpec().GetFileName(), step.LineNo, step.InConcept()) 106 logger.Error(false, specInfo) 107 stacktrace := prepStacktrace(stepRes.ProtoStepExecResult().GetExecutionResult().GetStackTrace()) 108 logger.Error(false, stacktrace) 109 110 failureMsg := formatErrorFragment(stepText, c.indentation) + formatErrorFragment(specInfo, c.indentation) + formatErrorFragment(errMsg, c.indentation) + formatErrorFragment(stacktrace, c.indentation) 111 _, err := c.sceFailuresBuf.WriteString(failureMsg) 112 if err != nil { 113 logger.Errorf(true, "Error writing to scenario failure buffer: %s", err.Error()) 114 } 115 } 116 printHookFailureCC(c, res, res.GetPostHook) 117 c.indentation -= stepIndentation 118 } 119 120 func (c *coloredConsole) ConceptStart(conceptHeading string) { 121 c.indentation += stepIndentation 122 logger.Debug(false, conceptHeading) 123 } 124 125 func (c *coloredConsole) ConceptEnd(res result.Result) { 126 c.indentation -= stepIndentation 127 } 128 129 func (c *coloredConsole) SuiteEnd(res result.Result) { 130 suiteRes := res.(*result.SuiteResult) 131 printHookFailureCC(c, res, res.GetPreHook) 132 printHookFailureCC(c, res, res.GetPostHook) 133 for _, e := range suiteRes.UnhandledErrors { 134 logger.Error(false, e.Error()) 135 c.displayMessage(indent(e.Error(), c.indentation+errorIndentation)+newline, ct.Red) 136 } 137 } 138 139 func (c *coloredConsole) DataTable(table string) { 140 logger.Debug(false, table) 141 c.displayMessage(table, ct.Yellow) 142 c.writer.Reset() 143 } 144 145 func (c *coloredConsole) Errorf(text string, args ...interface{}) { 146 msg := fmt.Sprintf(text, args...) 147 logger.Error(false, msg) 148 msg = indent(msg, c.indentation+errorIndentation) + newline 149 c.displayMessage(msg, ct.Red) 150 } 151 152 // Write writes the bytes to console via goterminal's writer. 153 // This is called when any sysouts are to be printed on console. 154 func (c *coloredConsole) Write(b []byte) (int, error) { 155 text := string(b) 156 c.displayMessage(text, ct.None) 157 return len(b), nil 158 } 159 160 func (c *coloredConsole) displayMessage(msg string, color ct.Color) { 161 ct.Foreground(color, false) 162 defer ct.ResetColor() 163 fmt.Fprint(c.writer, msg) 164 c.writer.Print() 165 } 166 167 func printHookFailureCC(c *coloredConsole, res result.Result, hookFailure func() []*gauge_messages.ProtoHookFailure) bool { 168 if len(hookFailure()) > 0 { 169 errMsg := prepErrorMessage(hookFailure()[0].GetErrorMessage()) 170 logger.Error(false, errMsg) 171 stacktrace := prepStacktrace(hookFailure()[0].GetStackTrace()) 172 logger.Error(false, stacktrace) 173 c.displayMessage(newline+formatErrorFragment(errMsg, c.indentation)+formatErrorFragment(stacktrace, c.indentation), ct.Red) 174 return false 175 } 176 return true 177 }