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  }