1package godog 2 3import ( 4 "fmt" 5 "io" 6 "math" 7 "strings" 8 9 "github.com/cucumber/messages-go/v10" 10) 11 12func init() { 13 Format("progress", "Prints a character per step.", progressFunc) 14} 15 16func progressFunc(suite string, out io.Writer) Formatter { 17 steps := 0 18 return &progress{ 19 basefmt: newBaseFmt(suite, out), 20 stepsPerRow: 70, 21 steps: &steps, 22 } 23} 24 25type progress struct { 26 *basefmt 27 stepsPerRow int 28 steps *int 29} 30 31func (f *progress) Summary() { 32 left := math.Mod(float64(*f.steps), float64(f.stepsPerRow)) 33 if left != 0 { 34 if *f.steps > f.stepsPerRow { 35 fmt.Fprintf(f.out, s(f.stepsPerRow-int(left))+fmt.Sprintf(" %d\n", *f.steps)) 36 } else { 37 fmt.Fprintf(f.out, " %d\n", *f.steps) 38 } 39 } 40 41 var failedStepsOutput []string 42 for _, sr := range f.findStepResults(failed) { 43 if sr.status == failed { 44 sc := f.findScenario(sr.owner.AstNodeIds[0]) 45 scenarioDesc := fmt.Sprintf("%s: %s", sc.Keyword, sr.owner.Name) 46 scenarioLine := fmt.Sprintf("%s:%d", sr.owner.Uri, sc.Location.Line) 47 48 step := f.findStep(sr.step.AstNodeIds[0]) 49 stepDesc := strings.TrimSpace(step.Keyword) + " " + sr.step.Text 50 stepLine := fmt.Sprintf("%s:%d", sr.owner.Uri, step.Location.Line) 51 52 failedStepsOutput = append( 53 failedStepsOutput, 54 s(2)+red(scenarioDesc)+blackb(" # "+scenarioLine), 55 s(4)+red(stepDesc)+blackb(" # "+stepLine), 56 s(6)+red("Error: ")+redb(fmt.Sprintf("%+v", sr.err)), 57 "", 58 ) 59 } 60 } 61 62 if len(failedStepsOutput) > 0 { 63 fmt.Fprintln(f.out, "\n\n--- "+red("Failed steps:")+"\n") 64 fmt.Fprint(f.out, strings.Join(failedStepsOutput, "\n")) 65 } 66 fmt.Fprintln(f.out, "") 67 68 f.basefmt.Summary() 69} 70 71func (f *progress) step(res *stepResult) { 72 switch res.status { 73 case passed: 74 fmt.Fprint(f.out, green(".")) 75 case skipped: 76 fmt.Fprint(f.out, cyan("-")) 77 case failed: 78 fmt.Fprint(f.out, red("F")) 79 case undefined: 80 fmt.Fprint(f.out, yellow("U")) 81 case pending: 82 fmt.Fprint(f.out, yellow("P")) 83 } 84 85 *f.steps++ 86 87 if math.Mod(float64(*f.steps), float64(f.stepsPerRow)) == 0 { 88 fmt.Fprintf(f.out, " %d\n", *f.steps) 89 } 90} 91 92func (f *progress) Passed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) { 93 f.basefmt.Passed(pickle, step, match) 94 95 f.lock.Lock() 96 defer f.lock.Unlock() 97 98 f.step(f.lastStepResult()) 99} 100 101func (f *progress) Skipped(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) { 102 f.basefmt.Skipped(pickle, step, match) 103 104 f.lock.Lock() 105 defer f.lock.Unlock() 106 107 f.step(f.lastStepResult()) 108} 109 110func (f *progress) Undefined(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) { 111 f.basefmt.Undefined(pickle, step, match) 112 113 f.lock.Lock() 114 defer f.lock.Unlock() 115 116 f.step(f.lastStepResult()) 117} 118 119func (f *progress) Failed(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition, err error) { 120 f.basefmt.Failed(pickle, step, match, err) 121 122 f.lock.Lock() 123 defer f.lock.Unlock() 124 125 f.step(f.lastStepResult()) 126} 127 128func (f *progress) Pending(pickle *messages.Pickle, step *messages.Pickle_PickleStep, match *StepDefinition) { 129 f.basefmt.Pending(pickle, step, match) 130 131 f.lock.Lock() 132 defer f.lock.Unlock() 133 134 f.step(f.lastStepResult()) 135} 136 137func (f *progress) Sync(cf ConcurrentFormatter) { 138 if source, ok := cf.(*progress); ok { 139 f.basefmt.Sync(source.basefmt) 140 f.steps = source.steps 141 } 142} 143 144func (f *progress) Copy(cf ConcurrentFormatter) { 145 if source, ok := cf.(*progress); ok { 146 f.basefmt.Copy(source.basefmt) 147 } 148} 149