1*333d2b36SAndroid Build Coastguard Worker// Copyright 2018 Google Inc. All rights reserved. 2*333d2b36SAndroid Build Coastguard Worker// 3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*333d2b36SAndroid Build Coastguard Worker// 7*333d2b36SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*333d2b36SAndroid Build Coastguard Worker// 9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*333d2b36SAndroid Build Coastguard Worker// limitations under the License. 14*333d2b36SAndroid Build Coastguard Worker 15*333d2b36SAndroid Build Coastguard Workerpackage terminal 16*333d2b36SAndroid Build Coastguard Worker 17*333d2b36SAndroid Build Coastguard Workerimport ( 18*333d2b36SAndroid Build Coastguard Worker "bytes" 19*333d2b36SAndroid Build Coastguard Worker "fmt" 20*333d2b36SAndroid Build Coastguard Worker "os" 21*333d2b36SAndroid Build Coastguard Worker "syscall" 22*333d2b36SAndroid Build Coastguard Worker "testing" 23*333d2b36SAndroid Build Coastguard Worker 24*333d2b36SAndroid Build Coastguard Worker "android/soong/ui/status" 25*333d2b36SAndroid Build Coastguard Worker) 26*333d2b36SAndroid Build Coastguard Worker 27*333d2b36SAndroid Build Coastguard Workerfunc TestStatusOutput(t *testing.T) { 28*333d2b36SAndroid Build Coastguard Worker tests := []struct { 29*333d2b36SAndroid Build Coastguard Worker name string 30*333d2b36SAndroid Build Coastguard Worker calls func(stat status.StatusOutput) 31*333d2b36SAndroid Build Coastguard Worker smart string 32*333d2b36SAndroid Build Coastguard Worker simple string 33*333d2b36SAndroid Build Coastguard Worker }{ 34*333d2b36SAndroid Build Coastguard Worker { 35*333d2b36SAndroid Build Coastguard Worker name: "two actions", 36*333d2b36SAndroid Build Coastguard Worker calls: twoActions, 37*333d2b36SAndroid Build Coastguard Worker smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action2\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n", 38*333d2b36SAndroid Build Coastguard Worker simple: "[ 50% 1/2] action1\n[100% 2/2] action2\n", 39*333d2b36SAndroid Build Coastguard Worker }, 40*333d2b36SAndroid Build Coastguard Worker { 41*333d2b36SAndroid Build Coastguard Worker name: "two parallel actions", 42*333d2b36SAndroid Build Coastguard Worker calls: twoParallelActions, 43*333d2b36SAndroid Build Coastguard Worker smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n", 44*333d2b36SAndroid Build Coastguard Worker simple: "[ 50% 1/2] action1\n[100% 2/2] action2\n", 45*333d2b36SAndroid Build Coastguard Worker }, 46*333d2b36SAndroid Build Coastguard Worker { 47*333d2b36SAndroid Build Coastguard Worker name: "action with output", 48*333d2b36SAndroid Build Coastguard Worker calls: actionsWithOutput, 49*333d2b36SAndroid Build Coastguard Worker smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\noutput1\noutput2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n", 50*333d2b36SAndroid Build Coastguard Worker simple: "[ 33% 1/3] action1\n[ 66% 2/3] action2\noutput1\noutput2\n[100% 3/3] action3\n", 51*333d2b36SAndroid Build Coastguard Worker }, 52*333d2b36SAndroid Build Coastguard Worker { 53*333d2b36SAndroid Build Coastguard Worker name: "action with output without newline", 54*333d2b36SAndroid Build Coastguard Worker calls: actionsWithOutputWithoutNewline, 55*333d2b36SAndroid Build Coastguard Worker smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\noutput1\noutput2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n", 56*333d2b36SAndroid Build Coastguard Worker simple: "[ 33% 1/3] action1\n[ 66% 2/3] action2\noutput1\noutput2\n[100% 3/3] action3\n", 57*333d2b36SAndroid Build Coastguard Worker }, 58*333d2b36SAndroid Build Coastguard Worker { 59*333d2b36SAndroid Build Coastguard Worker name: "action with error", 60*333d2b36SAndroid Build Coastguard Worker calls: actionsWithError, 61*333d2b36SAndroid Build Coastguard Worker smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\n\x1b[31m\x1b[1mFAILED:\x1b[0m f1 f2\ntouch f1 f2\nerror1\nerror2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n", 62*333d2b36SAndroid Build Coastguard Worker simple: "[ 33% 1/3] action1\n[ 66% 2/3] action2\nFAILED: f1 f2\ntouch f1 f2\nerror1\nerror2\n[100% 3/3] action3\n", 63*333d2b36SAndroid Build Coastguard Worker }, 64*333d2b36SAndroid Build Coastguard Worker { 65*333d2b36SAndroid Build Coastguard Worker name: "action with empty description", 66*333d2b36SAndroid Build Coastguard Worker calls: actionWithEmptyDescription, 67*333d2b36SAndroid Build Coastguard Worker smart: "\r\x1b[1m[ 0% 0/1] command1\x1b[0m\x1b[K\r\x1b[1m[100% 1/1] command1\x1b[0m\x1b[K\n", 68*333d2b36SAndroid Build Coastguard Worker simple: "[100% 1/1] command1\n", 69*333d2b36SAndroid Build Coastguard Worker }, 70*333d2b36SAndroid Build Coastguard Worker { 71*333d2b36SAndroid Build Coastguard Worker name: "messages", 72*333d2b36SAndroid Build Coastguard Worker calls: actionsWithMessages, 73*333d2b36SAndroid Build Coastguard Worker smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1mstatus\x1b[0m\x1b[K\r\x1b[Kprint\n\x1b[31m\x1b[1mFAILED:\x1b[0m error\n\r\x1b[1m[ 50% 1/2] action2\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n", 74*333d2b36SAndroid Build Coastguard Worker simple: "[ 50% 1/2] action1\nstatus\nprint\nFAILED: error\n[100% 2/2] action2\n", 75*333d2b36SAndroid Build Coastguard Worker }, 76*333d2b36SAndroid Build Coastguard Worker { 77*333d2b36SAndroid Build Coastguard Worker name: "action with long description", 78*333d2b36SAndroid Build Coastguard Worker calls: actionWithLongDescription, 79*333d2b36SAndroid Build Coastguard Worker smart: "\r\x1b[1m[ 0% 0/2] action with very long descrip\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action with very long descrip\x1b[0m\x1b[K\n", 80*333d2b36SAndroid Build Coastguard Worker simple: "[ 50% 1/2] action with very long description to test eliding\n", 81*333d2b36SAndroid Build Coastguard Worker }, 82*333d2b36SAndroid Build Coastguard Worker { 83*333d2b36SAndroid Build Coastguard Worker name: "action with output with ansi codes", 84*333d2b36SAndroid Build Coastguard Worker calls: actionWithOutputWithAnsiCodes, 85*333d2b36SAndroid Build Coastguard Worker smart: "\r\x1b[1m[ 0% 0/1] action1\x1b[0m\x1b[K\r\x1b[1m[100% 1/1] action1\x1b[0m\x1b[K\n\x1b[31mcolor\x1b[0m\n\x1b[31mcolor message\x1b[0m\n", 86*333d2b36SAndroid Build Coastguard Worker simple: "[100% 1/1] action1\ncolor\ncolor message\n", 87*333d2b36SAndroid Build Coastguard Worker }, 88*333d2b36SAndroid Build Coastguard Worker } 89*333d2b36SAndroid Build Coastguard Worker 90*333d2b36SAndroid Build Coastguard Worker os.Setenv(tableHeightEnVar, "") 91*333d2b36SAndroid Build Coastguard Worker 92*333d2b36SAndroid Build Coastguard Worker for _, tt := range tests { 93*333d2b36SAndroid Build Coastguard Worker t.Run(tt.name, func(t *testing.T) { 94*333d2b36SAndroid Build Coastguard Worker 95*333d2b36SAndroid Build Coastguard Worker t.Run("smart", func(t *testing.T) { 96*333d2b36SAndroid Build Coastguard Worker smart := &fakeSmartTerminal{termWidth: 40} 97*333d2b36SAndroid Build Coastguard Worker stat := NewStatusOutput(smart, "", false, false, false) 98*333d2b36SAndroid Build Coastguard Worker tt.calls(stat) 99*333d2b36SAndroid Build Coastguard Worker stat.Flush() 100*333d2b36SAndroid Build Coastguard Worker 101*333d2b36SAndroid Build Coastguard Worker if g, w := smart.String(), tt.smart; g != w { 102*333d2b36SAndroid Build Coastguard Worker t.Errorf("want:\n%q\ngot:\n%q", w, g) 103*333d2b36SAndroid Build Coastguard Worker } 104*333d2b36SAndroid Build Coastguard Worker }) 105*333d2b36SAndroid Build Coastguard Worker 106*333d2b36SAndroid Build Coastguard Worker t.Run("simple", func(t *testing.T) { 107*333d2b36SAndroid Build Coastguard Worker simple := &bytes.Buffer{} 108*333d2b36SAndroid Build Coastguard Worker stat := NewStatusOutput(simple, "", false, false, false) 109*333d2b36SAndroid Build Coastguard Worker tt.calls(stat) 110*333d2b36SAndroid Build Coastguard Worker stat.Flush() 111*333d2b36SAndroid Build Coastguard Worker 112*333d2b36SAndroid Build Coastguard Worker if g, w := simple.String(), tt.simple; g != w { 113*333d2b36SAndroid Build Coastguard Worker t.Errorf("want:\n%q\ngot:\n%q", w, g) 114*333d2b36SAndroid Build Coastguard Worker } 115*333d2b36SAndroid Build Coastguard Worker }) 116*333d2b36SAndroid Build Coastguard Worker 117*333d2b36SAndroid Build Coastguard Worker t.Run("force simple", func(t *testing.T) { 118*333d2b36SAndroid Build Coastguard Worker smart := &fakeSmartTerminal{termWidth: 40} 119*333d2b36SAndroid Build Coastguard Worker stat := NewStatusOutput(smart, "", true, false, false) 120*333d2b36SAndroid Build Coastguard Worker tt.calls(stat) 121*333d2b36SAndroid Build Coastguard Worker stat.Flush() 122*333d2b36SAndroid Build Coastguard Worker 123*333d2b36SAndroid Build Coastguard Worker if g, w := smart.String(), tt.simple; g != w { 124*333d2b36SAndroid Build Coastguard Worker t.Errorf("want:\n%q\ngot:\n%q", w, g) 125*333d2b36SAndroid Build Coastguard Worker } 126*333d2b36SAndroid Build Coastguard Worker }) 127*333d2b36SAndroid Build Coastguard Worker }) 128*333d2b36SAndroid Build Coastguard Worker } 129*333d2b36SAndroid Build Coastguard Worker} 130*333d2b36SAndroid Build Coastguard Worker 131*333d2b36SAndroid Build Coastguard Workertype runner struct { 132*333d2b36SAndroid Build Coastguard Worker counts status.Counts 133*333d2b36SAndroid Build Coastguard Worker stat status.StatusOutput 134*333d2b36SAndroid Build Coastguard Worker} 135*333d2b36SAndroid Build Coastguard Worker 136*333d2b36SAndroid Build Coastguard Workerfunc newRunner(stat status.StatusOutput, totalActions int) *runner { 137*333d2b36SAndroid Build Coastguard Worker return &runner{ 138*333d2b36SAndroid Build Coastguard Worker counts: status.Counts{TotalActions: totalActions}, 139*333d2b36SAndroid Build Coastguard Worker stat: stat, 140*333d2b36SAndroid Build Coastguard Worker } 141*333d2b36SAndroid Build Coastguard Worker} 142*333d2b36SAndroid Build Coastguard Worker 143*333d2b36SAndroid Build Coastguard Workerfunc (r *runner) startAction(action *status.Action) { 144*333d2b36SAndroid Build Coastguard Worker r.counts.StartedActions++ 145*333d2b36SAndroid Build Coastguard Worker r.counts.RunningActions++ 146*333d2b36SAndroid Build Coastguard Worker r.stat.StartAction(action, r.counts) 147*333d2b36SAndroid Build Coastguard Worker} 148*333d2b36SAndroid Build Coastguard Worker 149*333d2b36SAndroid Build Coastguard Workerfunc (r *runner) finishAction(result status.ActionResult) { 150*333d2b36SAndroid Build Coastguard Worker r.counts.FinishedActions++ 151*333d2b36SAndroid Build Coastguard Worker r.counts.RunningActions-- 152*333d2b36SAndroid Build Coastguard Worker r.stat.FinishAction(result, r.counts) 153*333d2b36SAndroid Build Coastguard Worker} 154*333d2b36SAndroid Build Coastguard Worker 155*333d2b36SAndroid Build Coastguard Workerfunc (r *runner) finishAndStartAction(result status.ActionResult, action *status.Action) { 156*333d2b36SAndroid Build Coastguard Worker r.counts.FinishedActions++ 157*333d2b36SAndroid Build Coastguard Worker r.stat.FinishAction(result, r.counts) 158*333d2b36SAndroid Build Coastguard Worker 159*333d2b36SAndroid Build Coastguard Worker r.counts.StartedActions++ 160*333d2b36SAndroid Build Coastguard Worker r.stat.StartAction(action, r.counts) 161*333d2b36SAndroid Build Coastguard Worker} 162*333d2b36SAndroid Build Coastguard Worker 163*333d2b36SAndroid Build Coastguard Workervar ( 164*333d2b36SAndroid Build Coastguard Worker action1 = &status.Action{Description: "action1"} 165*333d2b36SAndroid Build Coastguard Worker result1 = status.ActionResult{Action: action1} 166*333d2b36SAndroid Build Coastguard Worker action2 = &status.Action{Description: "action2"} 167*333d2b36SAndroid Build Coastguard Worker result2 = status.ActionResult{Action: action2} 168*333d2b36SAndroid Build Coastguard Worker action3 = &status.Action{Description: "action3"} 169*333d2b36SAndroid Build Coastguard Worker result3 = status.ActionResult{Action: action3} 170*333d2b36SAndroid Build Coastguard Worker) 171*333d2b36SAndroid Build Coastguard Worker 172*333d2b36SAndroid Build Coastguard Workerfunc twoActions(stat status.StatusOutput) { 173*333d2b36SAndroid Build Coastguard Worker runner := newRunner(stat, 2) 174*333d2b36SAndroid Build Coastguard Worker runner.startAction(action1) 175*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result1) 176*333d2b36SAndroid Build Coastguard Worker runner.startAction(action2) 177*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result2) 178*333d2b36SAndroid Build Coastguard Worker} 179*333d2b36SAndroid Build Coastguard Worker 180*333d2b36SAndroid Build Coastguard Workerfunc twoParallelActions(stat status.StatusOutput) { 181*333d2b36SAndroid Build Coastguard Worker runner := newRunner(stat, 2) 182*333d2b36SAndroid Build Coastguard Worker runner.startAction(action1) 183*333d2b36SAndroid Build Coastguard Worker runner.startAction(action2) 184*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result1) 185*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result2) 186*333d2b36SAndroid Build Coastguard Worker} 187*333d2b36SAndroid Build Coastguard Worker 188*333d2b36SAndroid Build Coastguard Workerfunc actionsWithOutput(stat status.StatusOutput) { 189*333d2b36SAndroid Build Coastguard Worker result2WithOutput := status.ActionResult{Action: action2, Output: "output1\noutput2\n"} 190*333d2b36SAndroid Build Coastguard Worker 191*333d2b36SAndroid Build Coastguard Worker runner := newRunner(stat, 3) 192*333d2b36SAndroid Build Coastguard Worker runner.startAction(action1) 193*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result1) 194*333d2b36SAndroid Build Coastguard Worker runner.startAction(action2) 195*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result2WithOutput) 196*333d2b36SAndroid Build Coastguard Worker runner.startAction(action3) 197*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result3) 198*333d2b36SAndroid Build Coastguard Worker} 199*333d2b36SAndroid Build Coastguard Worker 200*333d2b36SAndroid Build Coastguard Workerfunc actionsWithOutputWithoutNewline(stat status.StatusOutput) { 201*333d2b36SAndroid Build Coastguard Worker result2WithOutputWithoutNewline := status.ActionResult{Action: action2, Output: "output1\noutput2"} 202*333d2b36SAndroid Build Coastguard Worker 203*333d2b36SAndroid Build Coastguard Worker runner := newRunner(stat, 3) 204*333d2b36SAndroid Build Coastguard Worker runner.startAction(action1) 205*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result1) 206*333d2b36SAndroid Build Coastguard Worker runner.startAction(action2) 207*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result2WithOutputWithoutNewline) 208*333d2b36SAndroid Build Coastguard Worker runner.startAction(action3) 209*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result3) 210*333d2b36SAndroid Build Coastguard Worker} 211*333d2b36SAndroid Build Coastguard Worker 212*333d2b36SAndroid Build Coastguard Workerfunc actionsWithError(stat status.StatusOutput) { 213*333d2b36SAndroid Build Coastguard Worker action2WithError := &status.Action{Description: "action2", Outputs: []string{"f1", "f2"}, Command: "touch f1 f2"} 214*333d2b36SAndroid Build Coastguard Worker result2WithError := status.ActionResult{Action: action2WithError, Output: "error1\nerror2\n", Error: fmt.Errorf("error1")} 215*333d2b36SAndroid Build Coastguard Worker 216*333d2b36SAndroid Build Coastguard Worker runner := newRunner(stat, 3) 217*333d2b36SAndroid Build Coastguard Worker runner.startAction(action1) 218*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result1) 219*333d2b36SAndroid Build Coastguard Worker runner.startAction(action2WithError) 220*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result2WithError) 221*333d2b36SAndroid Build Coastguard Worker runner.startAction(action3) 222*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result3) 223*333d2b36SAndroid Build Coastguard Worker} 224*333d2b36SAndroid Build Coastguard Worker 225*333d2b36SAndroid Build Coastguard Workerfunc actionWithEmptyDescription(stat status.StatusOutput) { 226*333d2b36SAndroid Build Coastguard Worker action1 := &status.Action{Command: "command1"} 227*333d2b36SAndroid Build Coastguard Worker result1 := status.ActionResult{Action: action1} 228*333d2b36SAndroid Build Coastguard Worker 229*333d2b36SAndroid Build Coastguard Worker runner := newRunner(stat, 1) 230*333d2b36SAndroid Build Coastguard Worker runner.startAction(action1) 231*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result1) 232*333d2b36SAndroid Build Coastguard Worker} 233*333d2b36SAndroid Build Coastguard Worker 234*333d2b36SAndroid Build Coastguard Workerfunc actionsWithMessages(stat status.StatusOutput) { 235*333d2b36SAndroid Build Coastguard Worker runner := newRunner(stat, 2) 236*333d2b36SAndroid Build Coastguard Worker 237*333d2b36SAndroid Build Coastguard Worker runner.startAction(action1) 238*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result1) 239*333d2b36SAndroid Build Coastguard Worker 240*333d2b36SAndroid Build Coastguard Worker stat.Message(status.VerboseLvl, "verbose") 241*333d2b36SAndroid Build Coastguard Worker stat.Message(status.StatusLvl, "status") 242*333d2b36SAndroid Build Coastguard Worker stat.Message(status.PrintLvl, "print") 243*333d2b36SAndroid Build Coastguard Worker stat.Message(status.ErrorLvl, "error") 244*333d2b36SAndroid Build Coastguard Worker 245*333d2b36SAndroid Build Coastguard Worker runner.startAction(action2) 246*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result2) 247*333d2b36SAndroid Build Coastguard Worker} 248*333d2b36SAndroid Build Coastguard Worker 249*333d2b36SAndroid Build Coastguard Workerfunc actionWithLongDescription(stat status.StatusOutput) { 250*333d2b36SAndroid Build Coastguard Worker action1 := &status.Action{Description: "action with very long description to test eliding"} 251*333d2b36SAndroid Build Coastguard Worker result1 := status.ActionResult{Action: action1} 252*333d2b36SAndroid Build Coastguard Worker 253*333d2b36SAndroid Build Coastguard Worker runner := newRunner(stat, 2) 254*333d2b36SAndroid Build Coastguard Worker 255*333d2b36SAndroid Build Coastguard Worker runner.startAction(action1) 256*333d2b36SAndroid Build Coastguard Worker 257*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result1) 258*333d2b36SAndroid Build Coastguard Worker} 259*333d2b36SAndroid Build Coastguard Worker 260*333d2b36SAndroid Build Coastguard Workerfunc actionWithOutputWithAnsiCodes(stat status.StatusOutput) { 261*333d2b36SAndroid Build Coastguard Worker result1WithOutputWithAnsiCodes := status.ActionResult{Action: action1, Output: "\x1b[31mcolor\x1b[0m"} 262*333d2b36SAndroid Build Coastguard Worker 263*333d2b36SAndroid Build Coastguard Worker runner := newRunner(stat, 1) 264*333d2b36SAndroid Build Coastguard Worker runner.startAction(action1) 265*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result1WithOutputWithAnsiCodes) 266*333d2b36SAndroid Build Coastguard Worker 267*333d2b36SAndroid Build Coastguard Worker stat.Message(status.PrintLvl, "\x1b[31mcolor message\x1b[0m") 268*333d2b36SAndroid Build Coastguard Worker} 269*333d2b36SAndroid Build Coastguard Worker 270*333d2b36SAndroid Build Coastguard Workerfunc TestSmartStatusOutputWidthChange(t *testing.T) { 271*333d2b36SAndroid Build Coastguard Worker os.Setenv(tableHeightEnVar, "") 272*333d2b36SAndroid Build Coastguard Worker 273*333d2b36SAndroid Build Coastguard Worker smart := &fakeSmartTerminal{termWidth: 40} 274*333d2b36SAndroid Build Coastguard Worker stat := NewStatusOutput(smart, "", false, false, false) 275*333d2b36SAndroid Build Coastguard Worker smartStat := stat.(*smartStatusOutput) 276*333d2b36SAndroid Build Coastguard Worker smartStat.sigwinchHandled = make(chan bool) 277*333d2b36SAndroid Build Coastguard Worker 278*333d2b36SAndroid Build Coastguard Worker runner := newRunner(stat, 2) 279*333d2b36SAndroid Build Coastguard Worker 280*333d2b36SAndroid Build Coastguard Worker action := &status.Action{Description: "action with very long description to test eliding"} 281*333d2b36SAndroid Build Coastguard Worker result := status.ActionResult{Action: action} 282*333d2b36SAndroid Build Coastguard Worker 283*333d2b36SAndroid Build Coastguard Worker runner.startAction(action) 284*333d2b36SAndroid Build Coastguard Worker smart.termWidth = 30 285*333d2b36SAndroid Build Coastguard Worker // Fake a SIGWINCH 286*333d2b36SAndroid Build Coastguard Worker smartStat.sigwinch <- syscall.SIGWINCH 287*333d2b36SAndroid Build Coastguard Worker <-smartStat.sigwinchHandled 288*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result) 289*333d2b36SAndroid Build Coastguard Worker 290*333d2b36SAndroid Build Coastguard Worker stat.Flush() 291*333d2b36SAndroid Build Coastguard Worker 292*333d2b36SAndroid Build Coastguard Worker w := "\r\x1b[1m[ 0% 0/2] action with very long descrip\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action with very lo\x1b[0m\x1b[K\n" 293*333d2b36SAndroid Build Coastguard Worker 294*333d2b36SAndroid Build Coastguard Worker if g := smart.String(); g != w { 295*333d2b36SAndroid Build Coastguard Worker t.Errorf("want:\n%q\ngot:\n%q", w, g) 296*333d2b36SAndroid Build Coastguard Worker } 297*333d2b36SAndroid Build Coastguard Worker} 298*333d2b36SAndroid Build Coastguard Worker 299*333d2b36SAndroid Build Coastguard Workerfunc TestSmartStatusDoesntHideAfterSucecss(t *testing.T) { 300*333d2b36SAndroid Build Coastguard Worker os.Setenv(tableHeightEnVar, "") 301*333d2b36SAndroid Build Coastguard Worker 302*333d2b36SAndroid Build Coastguard Worker smart := &fakeSmartTerminal{termWidth: 40} 303*333d2b36SAndroid Build Coastguard Worker stat := NewStatusOutput(smart, "", false, false, false) 304*333d2b36SAndroid Build Coastguard Worker smartStat := stat.(*smartStatusOutput) 305*333d2b36SAndroid Build Coastguard Worker smartStat.sigwinchHandled = make(chan bool) 306*333d2b36SAndroid Build Coastguard Worker 307*333d2b36SAndroid Build Coastguard Worker runner := newRunner(stat, 2) 308*333d2b36SAndroid Build Coastguard Worker 309*333d2b36SAndroid Build Coastguard Worker action1 := &status.Action{Description: "action1"} 310*333d2b36SAndroid Build Coastguard Worker result1 := status.ActionResult{ 311*333d2b36SAndroid Build Coastguard Worker Action: action1, 312*333d2b36SAndroid Build Coastguard Worker Output: "Output1", 313*333d2b36SAndroid Build Coastguard Worker } 314*333d2b36SAndroid Build Coastguard Worker 315*333d2b36SAndroid Build Coastguard Worker action2 := &status.Action{Description: "action2"} 316*333d2b36SAndroid Build Coastguard Worker result2 := status.ActionResult{ 317*333d2b36SAndroid Build Coastguard Worker Action: action2, 318*333d2b36SAndroid Build Coastguard Worker Output: "Output2", 319*333d2b36SAndroid Build Coastguard Worker } 320*333d2b36SAndroid Build Coastguard Worker 321*333d2b36SAndroid Build Coastguard Worker runner.startAction(action1) 322*333d2b36SAndroid Build Coastguard Worker runner.startAction(action2) 323*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result1) 324*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result2) 325*333d2b36SAndroid Build Coastguard Worker 326*333d2b36SAndroid Build Coastguard Worker stat.Flush() 327*333d2b36SAndroid Build Coastguard Worker 328*333d2b36SAndroid Build Coastguard Worker w := "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\nOutput1\n\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\nOutput2\n" 329*333d2b36SAndroid Build Coastguard Worker 330*333d2b36SAndroid Build Coastguard Worker if g := smart.String(); g != w { 331*333d2b36SAndroid Build Coastguard Worker t.Errorf("want:\n%q\ngot:\n%q", w, g) 332*333d2b36SAndroid Build Coastguard Worker } 333*333d2b36SAndroid Build Coastguard Worker} 334*333d2b36SAndroid Build Coastguard Worker 335*333d2b36SAndroid Build Coastguard Workerfunc TestSmartStatusHideAfterFailure(t *testing.T) { 336*333d2b36SAndroid Build Coastguard Worker os.Setenv(tableHeightEnVar, "") 337*333d2b36SAndroid Build Coastguard Worker 338*333d2b36SAndroid Build Coastguard Worker smart := &fakeSmartTerminal{termWidth: 40} 339*333d2b36SAndroid Build Coastguard Worker stat := NewStatusOutput(smart, "", false, false, false) 340*333d2b36SAndroid Build Coastguard Worker smartStat := stat.(*smartStatusOutput) 341*333d2b36SAndroid Build Coastguard Worker smartStat.sigwinchHandled = make(chan bool) 342*333d2b36SAndroid Build Coastguard Worker 343*333d2b36SAndroid Build Coastguard Worker runner := newRunner(stat, 2) 344*333d2b36SAndroid Build Coastguard Worker 345*333d2b36SAndroid Build Coastguard Worker action1 := &status.Action{Description: "action1"} 346*333d2b36SAndroid Build Coastguard Worker result1 := status.ActionResult{ 347*333d2b36SAndroid Build Coastguard Worker Action: action1, 348*333d2b36SAndroid Build Coastguard Worker Output: "Output1", 349*333d2b36SAndroid Build Coastguard Worker Error: fmt.Errorf("Error1"), 350*333d2b36SAndroid Build Coastguard Worker } 351*333d2b36SAndroid Build Coastguard Worker 352*333d2b36SAndroid Build Coastguard Worker action2 := &status.Action{Description: "action2"} 353*333d2b36SAndroid Build Coastguard Worker result2 := status.ActionResult{ 354*333d2b36SAndroid Build Coastguard Worker Action: action2, 355*333d2b36SAndroid Build Coastguard Worker Output: "Output2", 356*333d2b36SAndroid Build Coastguard Worker } 357*333d2b36SAndroid Build Coastguard Worker 358*333d2b36SAndroid Build Coastguard Worker runner.startAction(action1) 359*333d2b36SAndroid Build Coastguard Worker runner.startAction(action2) 360*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result1) 361*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result2) 362*333d2b36SAndroid Build Coastguard Worker 363*333d2b36SAndroid Build Coastguard Worker stat.Flush() 364*333d2b36SAndroid Build Coastguard Worker 365*333d2b36SAndroid Build Coastguard Worker w := "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\n\x1b[31m\x1b[1mFAILED:\x1b[0m \nOutput1\n\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\nThere was 1 action that completed after the action that failed. See verbose.log.gz for its output.\n" 366*333d2b36SAndroid Build Coastguard Worker 367*333d2b36SAndroid Build Coastguard Worker if g := smart.String(); g != w { 368*333d2b36SAndroid Build Coastguard Worker t.Errorf("want:\n%q\ngot:\n%q", w, g) 369*333d2b36SAndroid Build Coastguard Worker } 370*333d2b36SAndroid Build Coastguard Worker} 371*333d2b36SAndroid Build Coastguard Worker 372*333d2b36SAndroid Build Coastguard Workerfunc TestSmartStatusHideAfterFailurePlural(t *testing.T) { 373*333d2b36SAndroid Build Coastguard Worker os.Setenv(tableHeightEnVar, "") 374*333d2b36SAndroid Build Coastguard Worker 375*333d2b36SAndroid Build Coastguard Worker smart := &fakeSmartTerminal{termWidth: 40} 376*333d2b36SAndroid Build Coastguard Worker stat := NewStatusOutput(smart, "", false, false, false) 377*333d2b36SAndroid Build Coastguard Worker smartStat := stat.(*smartStatusOutput) 378*333d2b36SAndroid Build Coastguard Worker smartStat.sigwinchHandled = make(chan bool) 379*333d2b36SAndroid Build Coastguard Worker 380*333d2b36SAndroid Build Coastguard Worker runner := newRunner(stat, 2) 381*333d2b36SAndroid Build Coastguard Worker 382*333d2b36SAndroid Build Coastguard Worker action1 := &status.Action{Description: "action1"} 383*333d2b36SAndroid Build Coastguard Worker result1 := status.ActionResult{ 384*333d2b36SAndroid Build Coastguard Worker Action: action1, 385*333d2b36SAndroid Build Coastguard Worker Output: "Output1", 386*333d2b36SAndroid Build Coastguard Worker Error: fmt.Errorf("Error1"), 387*333d2b36SAndroid Build Coastguard Worker } 388*333d2b36SAndroid Build Coastguard Worker 389*333d2b36SAndroid Build Coastguard Worker action2 := &status.Action{Description: "action2"} 390*333d2b36SAndroid Build Coastguard Worker result2 := status.ActionResult{ 391*333d2b36SAndroid Build Coastguard Worker Action: action2, 392*333d2b36SAndroid Build Coastguard Worker Output: "Output2", 393*333d2b36SAndroid Build Coastguard Worker } 394*333d2b36SAndroid Build Coastguard Worker 395*333d2b36SAndroid Build Coastguard Worker action3 := &status.Action{Description: "action3"} 396*333d2b36SAndroid Build Coastguard Worker result3 := status.ActionResult{ 397*333d2b36SAndroid Build Coastguard Worker Action: action3, 398*333d2b36SAndroid Build Coastguard Worker Output: "Output3", 399*333d2b36SAndroid Build Coastguard Worker } 400*333d2b36SAndroid Build Coastguard Worker 401*333d2b36SAndroid Build Coastguard Worker runner.startAction(action1) 402*333d2b36SAndroid Build Coastguard Worker runner.startAction(action2) 403*333d2b36SAndroid Build Coastguard Worker runner.startAction(action3) 404*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result1) 405*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result2) 406*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result3) 407*333d2b36SAndroid Build Coastguard Worker 408*333d2b36SAndroid Build Coastguard Worker stat.Flush() 409*333d2b36SAndroid Build Coastguard Worker 410*333d2b36SAndroid Build Coastguard Worker w := "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action3\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\n\x1b[31m\x1b[1mFAILED:\x1b[0m \nOutput1\n\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\r\x1b[1m[150% 3/2] action3\x1b[0m\x1b[K\nThere were 2 actions that completed after the action that failed. See verbose.log.gz for their output.\n" 411*333d2b36SAndroid Build Coastguard Worker 412*333d2b36SAndroid Build Coastguard Worker if g := smart.String(); g != w { 413*333d2b36SAndroid Build Coastguard Worker t.Errorf("want:\n%q\ngot:\n%q", w, g) 414*333d2b36SAndroid Build Coastguard Worker } 415*333d2b36SAndroid Build Coastguard Worker} 416*333d2b36SAndroid Build Coastguard Worker 417*333d2b36SAndroid Build Coastguard Workerfunc TestSmartStatusDontHideErrorAfterFailure(t *testing.T) { 418*333d2b36SAndroid Build Coastguard Worker os.Setenv(tableHeightEnVar, "") 419*333d2b36SAndroid Build Coastguard Worker 420*333d2b36SAndroid Build Coastguard Worker smart := &fakeSmartTerminal{termWidth: 40} 421*333d2b36SAndroid Build Coastguard Worker stat := NewStatusOutput(smart, "", false, false, false) 422*333d2b36SAndroid Build Coastguard Worker smartStat := stat.(*smartStatusOutput) 423*333d2b36SAndroid Build Coastguard Worker smartStat.sigwinchHandled = make(chan bool) 424*333d2b36SAndroid Build Coastguard Worker 425*333d2b36SAndroid Build Coastguard Worker runner := newRunner(stat, 2) 426*333d2b36SAndroid Build Coastguard Worker 427*333d2b36SAndroid Build Coastguard Worker action1 := &status.Action{Description: "action1"} 428*333d2b36SAndroid Build Coastguard Worker result1 := status.ActionResult{ 429*333d2b36SAndroid Build Coastguard Worker Action: action1, 430*333d2b36SAndroid Build Coastguard Worker Output: "Output1", 431*333d2b36SAndroid Build Coastguard Worker Error: fmt.Errorf("Error1"), 432*333d2b36SAndroid Build Coastguard Worker } 433*333d2b36SAndroid Build Coastguard Worker 434*333d2b36SAndroid Build Coastguard Worker action2 := &status.Action{Description: "action2"} 435*333d2b36SAndroid Build Coastguard Worker result2 := status.ActionResult{ 436*333d2b36SAndroid Build Coastguard Worker Action: action2, 437*333d2b36SAndroid Build Coastguard Worker Output: "Output2", 438*333d2b36SAndroid Build Coastguard Worker Error: fmt.Errorf("Error1"), 439*333d2b36SAndroid Build Coastguard Worker } 440*333d2b36SAndroid Build Coastguard Worker 441*333d2b36SAndroid Build Coastguard Worker runner.startAction(action1) 442*333d2b36SAndroid Build Coastguard Worker runner.startAction(action2) 443*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result1) 444*333d2b36SAndroid Build Coastguard Worker runner.finishAction(result2) 445*333d2b36SAndroid Build Coastguard Worker 446*333d2b36SAndroid Build Coastguard Worker stat.Flush() 447*333d2b36SAndroid Build Coastguard Worker 448*333d2b36SAndroid Build Coastguard Worker w := "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\n\x1b[31m\x1b[1mFAILED:\x1b[0m \nOutput1\n\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n\x1b[31m\x1b[1mFAILED:\x1b[0m \nOutput2\n" 449*333d2b36SAndroid Build Coastguard Worker 450*333d2b36SAndroid Build Coastguard Worker if g := smart.String(); g != w { 451*333d2b36SAndroid Build Coastguard Worker t.Errorf("want:\n%q\ngot:\n%q", w, g) 452*333d2b36SAndroid Build Coastguard Worker } 453*333d2b36SAndroid Build Coastguard Worker} 454