mirror of
https://github.com/rocky-linux/peridot.git
synced 2024-11-27 07:26:26 +00:00
Neil Hanlon
e7b15b3cde
given a task ID, fetch its details and display them to a table or to json with `-o json`. Table view also adds a calculated task duration and can optionally include the submitter information as well as a link to logs for the task. * --no-color - to skip colorizing output * --L|--logs - include column with link to logs * --submitter - show submitter * --no-wait - control whether to wait until a task completes to output (table mode)
1183 lines
40 KiB
Go
1183 lines
40 KiB
Go
// Copyright 2014 Oleku Konko All rights reserved.
|
|
// Use of this source code is governed by a MIT
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// This module is a Table Writer API for the Go Programming Language.
|
|
// The protocols were written in pure Go and works on windows and unix systems
|
|
|
|
package tablewriter
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func checkEqual(t *testing.T, got, want interface{}, msgs ...interface{}) {
|
|
if !reflect.DeepEqual(got, want) {
|
|
buf := bytes.Buffer{}
|
|
buf.WriteString("got:\n[%v]\nwant:\n[%v]\n")
|
|
for _, v := range msgs {
|
|
buf.WriteString(v.(string))
|
|
}
|
|
t.Errorf(buf.String(), got, want)
|
|
}
|
|
}
|
|
|
|
func ExampleShort() {
|
|
data := [][]string{
|
|
{"A", "The Good", "500"},
|
|
{"B", "The Very very Bad Man", "288"},
|
|
{"C", "The Ugly", "120"},
|
|
{"D", "The Gopher", "800"},
|
|
}
|
|
|
|
table := NewWriter(os.Stdout)
|
|
table.SetHeader([]string{"Name", "Sign", "Rating"})
|
|
|
|
for _, v := range data {
|
|
table.Append(v)
|
|
}
|
|
table.Render()
|
|
|
|
// Output: +------+-----------------------+--------+
|
|
// | NAME | SIGN | RATING |
|
|
// +------+-----------------------+--------+
|
|
// | A | The Good | 500 |
|
|
// | B | The Very very Bad Man | 288 |
|
|
// | C | The Ugly | 120 |
|
|
// | D | The Gopher | 800 |
|
|
// +------+-----------------------+--------+
|
|
}
|
|
|
|
func ExampleLong() {
|
|
data := [][]string{
|
|
{"Learn East has computers with adapted keyboards with enlarged print etc", " Some Data ", " Another Data"},
|
|
{"Instead of lining up the letters all ", "the way across, he splits the keyboard in two", "Like most ergonomic keyboards", "See Data"},
|
|
}
|
|
|
|
table := NewWriter(os.Stdout)
|
|
table.SetHeader([]string{"Name", "Sign", "Rating"})
|
|
table.SetCenterSeparator("*")
|
|
table.SetRowSeparator("=")
|
|
|
|
for _, v := range data {
|
|
table.Append(v)
|
|
}
|
|
table.Render()
|
|
|
|
// Output: *================================*================================*===============================*==========*
|
|
// | NAME | SIGN | RATING | |
|
|
// *================================*================================*===============================*==========*
|
|
// | Learn East has computers | Some Data | Another Data |
|
|
// | with adapted keyboards with | | |
|
|
// | enlarged print etc | | |
|
|
// | Instead of lining up the | the way across, he splits the | Like most ergonomic keyboards | See Data |
|
|
// | letters all | keyboard in two | | |
|
|
// *================================*================================*===============================*==========*
|
|
}
|
|
|
|
func ExampleCSV() {
|
|
table, _ := NewCSV(os.Stdout, "testdata/test.csv", true)
|
|
table.SetCenterSeparator("*")
|
|
table.SetRowSeparator("=")
|
|
|
|
table.Render()
|
|
|
|
// Output: *============*===========*=========*
|
|
// | FIRST NAME | LAST NAME | SSN |
|
|
// *============*===========*=========*
|
|
// | John | Barry | 123456 |
|
|
// | Kathy | Smith | 687987 |
|
|
// | Bob | McCornick | 3979870 |
|
|
// *============*===========*=========*
|
|
}
|
|
|
|
// TestNumLines to test the numbers of lines
|
|
func TestNumLines(t *testing.T) {
|
|
data := [][]string{
|
|
{"A", "The Good", "500"},
|
|
{"B", "The Very very Bad Man", "288"},
|
|
{"C", "The Ugly", "120"},
|
|
{"D", "The Gopher", "800"},
|
|
}
|
|
|
|
buf := &bytes.Buffer{}
|
|
table := NewWriter(buf)
|
|
table.SetHeader([]string{"Name", "Sign", "Rating"})
|
|
|
|
for i, v := range data {
|
|
table.Append(v)
|
|
checkEqual(t, table.NumLines(), i+1, "Number of lines failed")
|
|
}
|
|
|
|
checkEqual(t, table.NumLines(), len(data), "Number of lines failed")
|
|
}
|
|
|
|
func TestCSVInfo(t *testing.T) {
|
|
buf := &bytes.Buffer{}
|
|
table, err := NewCSV(buf, "testdata/test_info.csv", true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
table.SetAlignment(ALIGN_LEFT)
|
|
table.SetBorder(false)
|
|
table.Render()
|
|
|
|
got := buf.String()
|
|
want := ` FIELD | TYPE | NULL | KEY | DEFAULT | EXTRA
|
|
-----------+--------------+------+-----+---------+-----------------
|
|
user_id | smallint(5) | NO | PRI | NULL | auto_increment
|
|
username | varchar(10) | NO | | NULL |
|
|
password | varchar(100) | NO | | NULL |
|
|
`
|
|
checkEqual(t, got, want, "CSV info failed")
|
|
}
|
|
|
|
func TestCSVSeparator(t *testing.T) {
|
|
buf := &bytes.Buffer{}
|
|
table, err := NewCSV(buf, "testdata/test.csv", true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
table.SetRowLine(true)
|
|
table.SetCenterSeparator("+")
|
|
table.SetColumnSeparator("|")
|
|
table.SetRowSeparator("-")
|
|
table.SetAlignment(ALIGN_LEFT)
|
|
table.Render()
|
|
|
|
want := `+------------+-----------+---------+
|
|
| FIRST NAME | LAST NAME | SSN |
|
|
+------------+-----------+---------+
|
|
| John | Barry | 123456 |
|
|
+------------+-----------+---------+
|
|
| Kathy | Smith | 687987 |
|
|
+------------+-----------+---------+
|
|
| Bob | McCornick | 3979870 |
|
|
+------------+-----------+---------+
|
|
`
|
|
|
|
checkEqual(t, buf.String(), want, "CSV info failed")
|
|
}
|
|
|
|
func TestNoBorder(t *testing.T) {
|
|
data := [][]string{
|
|
{"1/1/2014", "Domain name", "2233", "$10.98"},
|
|
{"1/1/2014", "January Hosting", "2233", "$54.95"},
|
|
{"", " (empty)\n (empty)", "", ""},
|
|
{"1/4/2014", "February Hosting", "2233", "$51.00"},
|
|
{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"},
|
|
{"1/4/2014", " (Discount)", "2233", "-$1.00"},
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
table := NewWriter(&buf)
|
|
table.SetAutoWrapText(false)
|
|
table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
|
|
table.SetFooter([]string{"", "", "Total", "$145.93"}) // Add Footer
|
|
table.SetBorder(false) // Set Border to false
|
|
table.AppendBulk(data) // Add Bulk Data
|
|
table.Render()
|
|
|
|
want := ` DATE | DESCRIPTION | CV2 | AMOUNT
|
|
-----------+--------------------------+-------+----------
|
|
1/1/2014 | Domain name | 2233 | $10.98
|
|
1/1/2014 | January Hosting | 2233 | $54.95
|
|
| (empty) | |
|
|
| (empty) | |
|
|
1/4/2014 | February Hosting | 2233 | $51.00
|
|
1/4/2014 | February Extra Bandwidth | 2233 | $30.00
|
|
1/4/2014 | (Discount) | 2233 | -$1.00
|
|
-----------+--------------------------+-------+----------
|
|
TOTAL | $145.93
|
|
--------+----------
|
|
`
|
|
|
|
checkEqual(t, buf.String(), want, "border table rendering failed")
|
|
}
|
|
|
|
func TestWithBorder(t *testing.T) {
|
|
data := [][]string{
|
|
{"1/1/2014", "Domain name", "2233", "$10.98"},
|
|
{"1/1/2014", "January Hosting", "2233", "$54.95"},
|
|
{"", " (empty)\n (empty)", "", ""},
|
|
{"1/4/2014", "February Hosting", "2233", "$51.00"},
|
|
{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"},
|
|
{"1/4/2014", " (Discount)", "2233", "-$1.00"},
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
table := NewWriter(&buf)
|
|
table.SetAutoWrapText(false)
|
|
table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
|
|
table.SetFooter([]string{"", "", "Total", "$145.93"}) // Add Footer
|
|
table.AppendBulk(data) // Add Bulk Data
|
|
table.Render()
|
|
|
|
want := `+----------+--------------------------+-------+---------+
|
|
| DATE | DESCRIPTION | CV2 | AMOUNT |
|
|
+----------+--------------------------+-------+---------+
|
|
| 1/1/2014 | Domain name | 2233 | $10.98 |
|
|
| 1/1/2014 | January Hosting | 2233 | $54.95 |
|
|
| | (empty) | | |
|
|
| | (empty) | | |
|
|
| 1/4/2014 | February Hosting | 2233 | $51.00 |
|
|
| 1/4/2014 | February Extra Bandwidth | 2233 | $30.00 |
|
|
| 1/4/2014 | (Discount) | 2233 | -$1.00 |
|
|
+----------+--------------------------+-------+---------+
|
|
| TOTAL | $145.93 |
|
|
+----------+--------------------------+-------+---------+
|
|
`
|
|
|
|
checkEqual(t, buf.String(), want, "border table rendering failed")
|
|
}
|
|
|
|
func TestPrintingInMarkdown(t *testing.T) {
|
|
data := [][]string{
|
|
{"1/1/2014", "Domain name", "2233", "$10.98"},
|
|
{"1/1/2014", "January Hosting", "2233", "$54.95"},
|
|
{"1/4/2014", "February Hosting", "2233", "$51.00"},
|
|
{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"},
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
table := NewWriter(&buf)
|
|
table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
|
|
table.AppendBulk(data) // Add Bulk Data
|
|
table.SetBorders(Border{Left: true, Top: false, Right: true, Bottom: false})
|
|
table.SetCenterSeparator("|")
|
|
table.Render()
|
|
|
|
want := `| DATE | DESCRIPTION | CV2 | AMOUNT |
|
|
|----------|--------------------------|------|--------|
|
|
| 1/1/2014 | Domain name | 2233 | $10.98 |
|
|
| 1/1/2014 | January Hosting | 2233 | $54.95 |
|
|
| 1/4/2014 | February Hosting | 2233 | $51.00 |
|
|
| 1/4/2014 | February Extra Bandwidth | 2233 | $30.00 |
|
|
`
|
|
checkEqual(t, buf.String(), want, "border table rendering failed")
|
|
}
|
|
|
|
func TestPrintHeading(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
table := NewWriter(&buf)
|
|
table.SetHeader([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c"})
|
|
table.printHeading()
|
|
want := `| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C |
|
|
+---+---+---+---+---+---+---+---+---+---+---+---+
|
|
`
|
|
checkEqual(t, buf.String(), want, "header rendering failed")
|
|
}
|
|
|
|
func TestPrintHeadingWithoutAutoFormat(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
table := NewWriter(&buf)
|
|
table.SetHeader([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c"})
|
|
table.SetAutoFormatHeaders(false)
|
|
table.printHeading()
|
|
want := `| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c |
|
|
+---+---+---+---+---+---+---+---+---+---+---+---+
|
|
`
|
|
checkEqual(t, buf.String(), want, "header rendering failed")
|
|
}
|
|
|
|
func TestPrintFooter(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
table := NewWriter(&buf)
|
|
table.SetHeader([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c"})
|
|
table.SetFooter([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c"})
|
|
table.printFooter()
|
|
want := `| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C |
|
|
+---+---+---+---+---+---+---+---+---+---+---+---+
|
|
`
|
|
checkEqual(t, buf.String(), want, "footer rendering failed")
|
|
}
|
|
|
|
func TestPrintFooterWithoutAutoFormat(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
table := NewWriter(&buf)
|
|
table.SetAutoFormatHeaders(false)
|
|
table.SetHeader([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c"})
|
|
table.SetFooter([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c"})
|
|
table.printFooter()
|
|
want := `| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c |
|
|
+---+---+---+---+---+---+---+---+---+---+---+---+
|
|
`
|
|
checkEqual(t, buf.String(), want, "footer rendering failed")
|
|
}
|
|
|
|
func TestPrintShortCaption(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
data := [][]string{
|
|
{"A", "The Good", "500"},
|
|
{"B", "The Very very Bad Man", "288"},
|
|
{"C", "The Ugly", "120"},
|
|
{"D", "The Gopher", "800"},
|
|
}
|
|
|
|
table := NewWriter(&buf)
|
|
table.SetHeader([]string{"Name", "Sign", "Rating"})
|
|
table.SetCaption(true, "Short caption.")
|
|
|
|
for _, v := range data {
|
|
table.Append(v)
|
|
}
|
|
table.Render()
|
|
|
|
want := `+------+-----------------------+--------+
|
|
| NAME | SIGN | RATING |
|
|
+------+-----------------------+--------+
|
|
| A | The Good | 500 |
|
|
| B | The Very very Bad Man | 288 |
|
|
| C | The Ugly | 120 |
|
|
| D | The Gopher | 800 |
|
|
+------+-----------------------+--------+
|
|
Short caption.
|
|
`
|
|
checkEqual(t, buf.String(), want, "long caption for short example rendering failed")
|
|
}
|
|
|
|
func TestPrintLongCaptionWithShortExample(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
data := [][]string{
|
|
{"A", "The Good", "500"},
|
|
{"B", "The Very very Bad Man", "288"},
|
|
{"C", "The Ugly", "120"},
|
|
{"D", "The Gopher", "800"},
|
|
}
|
|
|
|
table := NewWriter(&buf)
|
|
table.SetHeader([]string{"Name", "Sign", "Rating"})
|
|
table.SetCaption(true, "This is a very long caption. The text should wrap. If not, we have a problem that needs to be solved.")
|
|
|
|
for _, v := range data {
|
|
table.Append(v)
|
|
}
|
|
table.Render()
|
|
|
|
want := `+------+-----------------------+--------+
|
|
| NAME | SIGN | RATING |
|
|
+------+-----------------------+--------+
|
|
| A | The Good | 500 |
|
|
| B | The Very very Bad Man | 288 |
|
|
| C | The Ugly | 120 |
|
|
| D | The Gopher | 800 |
|
|
+------+-----------------------+--------+
|
|
This is a very long caption. The text
|
|
should wrap. If not, we have a problem
|
|
that needs to be solved.
|
|
`
|
|
checkEqual(t, buf.String(), want, "long caption for short example rendering failed")
|
|
}
|
|
|
|
func TestPrintCaptionWithFooter(t *testing.T) {
|
|
data := [][]string{
|
|
{"1/1/2014", "Domain name", "2233", "$10.98"},
|
|
{"1/1/2014", "January Hosting", "2233", "$54.95"},
|
|
{"1/4/2014", "February Hosting", "2233", "$51.00"},
|
|
{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"},
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
table := NewWriter(&buf)
|
|
table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
|
|
table.SetFooter([]string{"", "", "Total", "$146.93"}) // Add Footer
|
|
table.SetCaption(true, "This is a very long caption. The text should wrap to the width of the table.") // Add caption
|
|
table.SetBorder(false) // Set Border to false
|
|
table.AppendBulk(data) // Add Bulk Data
|
|
table.Render()
|
|
|
|
want := ` DATE | DESCRIPTION | CV2 | AMOUNT
|
|
-----------+--------------------------+-------+----------
|
|
1/1/2014 | Domain name | 2233 | $10.98
|
|
1/1/2014 | January Hosting | 2233 | $54.95
|
|
1/4/2014 | February Hosting | 2233 | $51.00
|
|
1/4/2014 | February Extra Bandwidth | 2233 | $30.00
|
|
-----------+--------------------------+-------+----------
|
|
TOTAL | $146.93
|
|
--------+----------
|
|
This is a very long caption. The text should wrap to the
|
|
width of the table.
|
|
`
|
|
checkEqual(t, buf.String(), want, "border table rendering failed")
|
|
}
|
|
|
|
func TestPrintLongCaptionWithLongExample(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
data := [][]string{
|
|
{"Learn East has computers with adapted keyboards with enlarged print etc", "Some Data", "Another Data"},
|
|
{"Instead of lining up the letters all", "the way across, he splits the keyboard in two", "Like most ergonomic keyboards"},
|
|
}
|
|
|
|
table := NewWriter(&buf)
|
|
table.SetCaption(true, "This is a very long caption. The text should wrap. If not, we have a problem that needs to be solved.")
|
|
table.SetHeader([]string{"Name", "Sign", "Rating"})
|
|
|
|
for _, v := range data {
|
|
table.Append(v)
|
|
}
|
|
table.Render()
|
|
|
|
want := `+--------------------------------+--------------------------------+-------------------------------+
|
|
| NAME | SIGN | RATING |
|
|
+--------------------------------+--------------------------------+-------------------------------+
|
|
| Learn East has computers | Some Data | Another Data |
|
|
| with adapted keyboards with | | |
|
|
| enlarged print etc | | |
|
|
| Instead of lining up the | the way across, he splits the | Like most ergonomic keyboards |
|
|
| letters all | keyboard in two | |
|
|
+--------------------------------+--------------------------------+-------------------------------+
|
|
This is a very long caption. The text should wrap. If not, we have a problem that needs to be
|
|
solved.
|
|
`
|
|
checkEqual(t, buf.String(), want, "long caption for long example rendering failed")
|
|
}
|
|
|
|
func Example_autowrap() {
|
|
var multiline = `A multiline
|
|
string with some lines being really long.`
|
|
|
|
const (
|
|
testRow = iota
|
|
testHeader
|
|
testFooter
|
|
testFooter2
|
|
)
|
|
for mode := testRow; mode <= testFooter2; mode++ {
|
|
for _, autoFmt := range []bool{false, true} {
|
|
if mode == testRow && autoFmt {
|
|
// Nothing special to test, skip
|
|
continue
|
|
}
|
|
for _, autoWrap := range []bool{false, true} {
|
|
for _, reflow := range []bool{false, true} {
|
|
if !autoWrap && reflow {
|
|
// Invalid configuration, skip
|
|
continue
|
|
}
|
|
fmt.Println("mode", mode, "autoFmt", autoFmt, "autoWrap", autoWrap, "reflow", reflow)
|
|
t := NewWriter(os.Stdout)
|
|
t.SetAutoFormatHeaders(autoFmt)
|
|
t.SetAutoWrapText(autoWrap)
|
|
t.SetReflowDuringAutoWrap(reflow)
|
|
if mode == testHeader {
|
|
t.SetHeader([]string{"woo", multiline})
|
|
} else {
|
|
t.SetHeader([]string{"woo", "waa"})
|
|
}
|
|
if mode == testRow {
|
|
t.Append([]string{"woo", multiline})
|
|
} else {
|
|
t.Append([]string{"woo", "waa"})
|
|
}
|
|
if mode == testFooter {
|
|
t.SetFooter([]string{"woo", multiline})
|
|
} else if mode == testFooter2 {
|
|
t.SetFooter([]string{"", multiline})
|
|
} else {
|
|
t.SetFooter([]string{"woo", "waa"})
|
|
}
|
|
t.Render()
|
|
}
|
|
}
|
|
}
|
|
fmt.Println()
|
|
}
|
|
|
|
// Output:
|
|
// mode 0 autoFmt false autoWrap false reflow false
|
|
// +-----+-------------------------------------------+
|
|
// | woo | waa |
|
|
// +-----+-------------------------------------------+
|
|
// | woo | A multiline |
|
|
// | | string with some lines being really long. |
|
|
// +-----+-------------------------------------------+
|
|
// | woo | waa |
|
|
// +-----+-------------------------------------------+
|
|
// mode 0 autoFmt false autoWrap true reflow false
|
|
// +-----+--------------------------------+
|
|
// | woo | waa |
|
|
// +-----+--------------------------------+
|
|
// | woo | A multiline |
|
|
// | | |
|
|
// | | string with some lines being |
|
|
// | | really long. |
|
|
// +-----+--------------------------------+
|
|
// | woo | waa |
|
|
// +-----+--------------------------------+
|
|
// mode 0 autoFmt false autoWrap true reflow true
|
|
// +-----+--------------------------------+
|
|
// | woo | waa |
|
|
// +-----+--------------------------------+
|
|
// | woo | A multiline string with some |
|
|
// | | lines being really long. |
|
|
// +-----+--------------------------------+
|
|
// | woo | waa |
|
|
// +-----+--------------------------------+
|
|
//
|
|
// mode 1 autoFmt false autoWrap false reflow false
|
|
// +-----+-------------------------------------------+
|
|
// | woo | A multiline |
|
|
// | | string with some lines being really long. |
|
|
// +-----+-------------------------------------------+
|
|
// | woo | waa |
|
|
// +-----+-------------------------------------------+
|
|
// | woo | waa |
|
|
// +-----+-------------------------------------------+
|
|
// mode 1 autoFmt false autoWrap true reflow false
|
|
// +-----+--------------------------------+
|
|
// | woo | A multiline |
|
|
// | | |
|
|
// | | string with some lines being |
|
|
// | | really long. |
|
|
// +-----+--------------------------------+
|
|
// | woo | waa |
|
|
// +-----+--------------------------------+
|
|
// | woo | waa |
|
|
// +-----+--------------------------------+
|
|
// mode 1 autoFmt false autoWrap true reflow true
|
|
// +-----+--------------------------------+
|
|
// | woo | A multiline string with some |
|
|
// | | lines being really long. |
|
|
// +-----+--------------------------------+
|
|
// | woo | waa |
|
|
// +-----+--------------------------------+
|
|
// | woo | waa |
|
|
// +-----+--------------------------------+
|
|
// mode 1 autoFmt true autoWrap false reflow false
|
|
// +-----+-------------------------------------------+
|
|
// | WOO | A MULTILINE |
|
|
// | | STRING WITH SOME LINES BEING REALLY LONG |
|
|
// +-----+-------------------------------------------+
|
|
// | woo | waa |
|
|
// +-----+-------------------------------------------+
|
|
// | WOO | WAA |
|
|
// +-----+-------------------------------------------+
|
|
// mode 1 autoFmt true autoWrap true reflow false
|
|
// +-----+--------------------------------+
|
|
// | WOO | A MULTILINE |
|
|
// | | |
|
|
// | | STRING WITH SOME LINES BEING |
|
|
// | | REALLY LONG |
|
|
// +-----+--------------------------------+
|
|
// | woo | waa |
|
|
// +-----+--------------------------------+
|
|
// | WOO | WAA |
|
|
// +-----+--------------------------------+
|
|
// mode 1 autoFmt true autoWrap true reflow true
|
|
// +-----+--------------------------------+
|
|
// | WOO | A MULTILINE STRING WITH SOME |
|
|
// | | LINES BEING REALLY LONG |
|
|
// +-----+--------------------------------+
|
|
// | woo | waa |
|
|
// +-----+--------------------------------+
|
|
// | WOO | WAA |
|
|
// +-----+--------------------------------+
|
|
//
|
|
// mode 2 autoFmt false autoWrap false reflow false
|
|
// +-----+-------------------------------------------+
|
|
// | woo | waa |
|
|
// +-----+-------------------------------------------+
|
|
// | woo | waa |
|
|
// +-----+-------------------------------------------+
|
|
// | woo | A multiline |
|
|
// | | string with some lines being really long. |
|
|
// +-----+-------------------------------------------+
|
|
// mode 2 autoFmt false autoWrap true reflow false
|
|
// +-----+--------------------------------+
|
|
// | woo | waa |
|
|
// +-----+--------------------------------+
|
|
// | woo | waa |
|
|
// +-----+--------------------------------+
|
|
// | woo | A multiline |
|
|
// | | |
|
|
// | | string with some lines being |
|
|
// | | really long. |
|
|
// +-----+--------------------------------+
|
|
// mode 2 autoFmt false autoWrap true reflow true
|
|
// +-----+--------------------------------+
|
|
// | woo | waa |
|
|
// +-----+--------------------------------+
|
|
// | woo | waa |
|
|
// +-----+--------------------------------+
|
|
// | woo | A multiline string with some |
|
|
// | | lines being really long. |
|
|
// +-----+--------------------------------+
|
|
// mode 2 autoFmt true autoWrap false reflow false
|
|
// +-----+-------------------------------------------+
|
|
// | WOO | WAA |
|
|
// +-----+-------------------------------------------+
|
|
// | woo | waa |
|
|
// +-----+-------------------------------------------+
|
|
// | WOO | A MULTILINE |
|
|
// | | STRING WITH SOME LINES BEING REALLY LONG |
|
|
// +-----+-------------------------------------------+
|
|
// mode 2 autoFmt true autoWrap true reflow false
|
|
// +-----+--------------------------------+
|
|
// | WOO | WAA |
|
|
// +-----+--------------------------------+
|
|
// | woo | waa |
|
|
// +-----+--------------------------------+
|
|
// | WOO | A MULTILINE |
|
|
// | | |
|
|
// | | STRING WITH SOME LINES BEING |
|
|
// | | REALLY LONG |
|
|
// +-----+--------------------------------+
|
|
// mode 2 autoFmt true autoWrap true reflow true
|
|
// +-----+--------------------------------+
|
|
// | WOO | WAA |
|
|
// +-----+--------------------------------+
|
|
// | woo | waa |
|
|
// +-----+--------------------------------+
|
|
// | WOO | A MULTILINE STRING WITH SOME |
|
|
// | | LINES BEING REALLY LONG |
|
|
// +-----+--------------------------------+
|
|
//
|
|
// mode 3 autoFmt false autoWrap false reflow false
|
|
// +-----+-------------------------------------------+
|
|
// | woo | waa |
|
|
// +-----+-------------------------------------------+
|
|
// | woo | waa |
|
|
// +-----+-------------------------------------------+
|
|
// | A multiline |
|
|
// | string with some lines being really long. |
|
|
// +-----+-------------------------------------------+
|
|
// mode 3 autoFmt false autoWrap true reflow false
|
|
// +-----+--------------------------------+
|
|
// | woo | waa |
|
|
// +-----+--------------------------------+
|
|
// | woo | waa |
|
|
// +-----+--------------------------------+
|
|
// | A multiline |
|
|
// | |
|
|
// | string with some lines being |
|
|
// | really long. |
|
|
// +-----+--------------------------------+
|
|
// mode 3 autoFmt false autoWrap true reflow true
|
|
// +-----+--------------------------------+
|
|
// | woo | waa |
|
|
// +-----+--------------------------------+
|
|
// | woo | waa |
|
|
// +-----+--------------------------------+
|
|
// | A multiline string with some |
|
|
// | lines being really long. |
|
|
// +-----+--------------------------------+
|
|
// mode 3 autoFmt true autoWrap false reflow false
|
|
// +-----+-------------------------------------------+
|
|
// | WOO | WAA |
|
|
// +-----+-------------------------------------------+
|
|
// | woo | waa |
|
|
// +-----+-------------------------------------------+
|
|
// | A MULTILINE |
|
|
// | STRING WITH SOME LINES BEING REALLY LONG |
|
|
// +-----+-------------------------------------------+
|
|
// mode 3 autoFmt true autoWrap true reflow false
|
|
// +-----+--------------------------------+
|
|
// | WOO | WAA |
|
|
// +-----+--------------------------------+
|
|
// | woo | waa |
|
|
// +-----+--------------------------------+
|
|
// | A MULTILINE |
|
|
// | |
|
|
// | STRING WITH SOME LINES BEING |
|
|
// | REALLY LONG |
|
|
// +-----+--------------------------------+
|
|
// mode 3 autoFmt true autoWrap true reflow true
|
|
// +-----+--------------------------------+
|
|
// | WOO | WAA |
|
|
// +-----+--------------------------------+
|
|
// | woo | waa |
|
|
// +-----+--------------------------------+
|
|
// | A MULTILINE STRING WITH SOME |
|
|
// | LINES BEING REALLY LONG |
|
|
// +-----+--------------------------------+
|
|
}
|
|
|
|
func TestPrintLine(t *testing.T) {
|
|
header := make([]string, 12)
|
|
val := " "
|
|
want := ""
|
|
for i := range header {
|
|
header[i] = val
|
|
want = fmt.Sprintf("%s+-%s-", want, strings.Replace(val, " ", "-", -1))
|
|
val = val + " "
|
|
}
|
|
want = want + "+"
|
|
var buf bytes.Buffer
|
|
table := NewWriter(&buf)
|
|
table.SetHeader(header)
|
|
table.printLine(false)
|
|
checkEqual(t, buf.String(), want, "line rendering failed")
|
|
}
|
|
|
|
func TestAnsiStrip(t *testing.T) {
|
|
header := make([]string, 12)
|
|
val := " "
|
|
want := ""
|
|
for i := range header {
|
|
header[i] = "\033[43;30m" + val + "\033[00m"
|
|
want = fmt.Sprintf("%s+-%s-", want, strings.Replace(val, " ", "-", -1))
|
|
val = val + " "
|
|
}
|
|
want = want + "+"
|
|
var buf bytes.Buffer
|
|
table := NewWriter(&buf)
|
|
table.SetHeader(header)
|
|
table.printLine(false)
|
|
checkEqual(t, buf.String(), want, "line rendering failed")
|
|
}
|
|
|
|
func NewCustomizedTable(out io.Writer) *Table {
|
|
table := NewWriter(out)
|
|
table.SetCenterSeparator("")
|
|
table.SetColumnSeparator("")
|
|
table.SetRowSeparator("")
|
|
table.SetBorder(false)
|
|
table.SetAlignment(ALIGN_LEFT)
|
|
table.SetHeader([]string{})
|
|
return table
|
|
}
|
|
|
|
func TestSubclass(t *testing.T) {
|
|
buf := new(bytes.Buffer)
|
|
table := NewCustomizedTable(buf)
|
|
|
|
data := [][]string{
|
|
{"A", "The Good", "500"},
|
|
{"B", "The Very very Bad Man", "288"},
|
|
{"C", "The Ugly", "120"},
|
|
{"D", "The Gopher", "800"},
|
|
}
|
|
|
|
for _, v := range data {
|
|
table.Append(v)
|
|
}
|
|
table.Render()
|
|
|
|
want := ` A The Good 500
|
|
B The Very very Bad Man 288
|
|
C The Ugly 120
|
|
D The Gopher 800
|
|
`
|
|
checkEqual(t, buf.String(), want, "test subclass failed")
|
|
}
|
|
|
|
func TestAutoMergeRows(t *testing.T) {
|
|
data := [][]string{
|
|
{"A", "The Good", "500"},
|
|
{"A", "The Very very Bad Man", "288"},
|
|
{"B", "The Very very Bad Man", "120"},
|
|
{"B", "The Very very Bad Man", "200"},
|
|
}
|
|
var buf bytes.Buffer
|
|
table := NewWriter(&buf)
|
|
table.SetHeader([]string{"Name", "Sign", "Rating"})
|
|
|
|
for _, v := range data {
|
|
table.Append(v)
|
|
}
|
|
table.SetAutoMergeCells(true)
|
|
table.Render()
|
|
want := `+------+-----------------------+--------+
|
|
| NAME | SIGN | RATING |
|
|
+------+-----------------------+--------+
|
|
| A | The Good | 500 |
|
|
| | The Very very Bad Man | 288 |
|
|
| B | | 120 |
|
|
| | | 200 |
|
|
+------+-----------------------+--------+
|
|
`
|
|
got := buf.String()
|
|
if got != want {
|
|
t.Errorf("\ngot:\n%s\nwant:\n%s\n", got, want)
|
|
}
|
|
|
|
buf.Reset()
|
|
table = NewWriter(&buf)
|
|
table.SetHeader([]string{"Name", "Sign", "Rating"})
|
|
|
|
for _, v := range data {
|
|
table.Append(v)
|
|
}
|
|
table.SetAutoMergeCells(true)
|
|
table.SetRowLine(true)
|
|
table.Render()
|
|
want = `+------+-----------------------+--------+
|
|
| NAME | SIGN | RATING |
|
|
+------+-----------------------+--------+
|
|
| A | The Good | 500 |
|
|
+ +-----------------------+--------+
|
|
| | The Very very Bad Man | 288 |
|
|
+------+ +--------+
|
|
| B | | 120 |
|
|
+ + +--------+
|
|
| | | 200 |
|
|
+------+-----------------------+--------+
|
|
`
|
|
checkEqual(t, buf.String(), want)
|
|
|
|
buf.Reset()
|
|
table = NewWriter(&buf)
|
|
table.SetHeader([]string{"Name", "Sign", "Rating"})
|
|
|
|
dataWithlongText := [][]string{
|
|
{"A", "The Good", "500"},
|
|
{"A", "The Very very very very very Bad Man", "288"},
|
|
{"B", "The Very very very very very Bad Man", "120"},
|
|
{"C", "The Very very Bad Man", "200"},
|
|
}
|
|
table.AppendBulk(dataWithlongText)
|
|
table.SetAutoMergeCells(true)
|
|
table.SetRowLine(true)
|
|
table.Render()
|
|
want = `+------+--------------------------------+--------+
|
|
| NAME | SIGN | RATING |
|
|
+------+--------------------------------+--------+
|
|
| A | The Good | 500 |
|
|
+ +--------------------------------+--------+
|
|
| | The Very very very very very | 288 |
|
|
| | Bad Man | |
|
|
+------+ +--------+
|
|
| B | | 120 |
|
|
| | | |
|
|
+------+--------------------------------+--------+
|
|
| C | The Very very Bad Man | 200 |
|
|
+------+--------------------------------+--------+
|
|
`
|
|
checkEqual(t, buf.String(), want)
|
|
|
|
buf.Reset()
|
|
table = NewWriter(&buf)
|
|
table.SetHeader([]string{"Name", "Sign", "Rating"})
|
|
|
|
dataWithlongText2 := [][]string{
|
|
{"A", "The Good", "500"},
|
|
{"A", "The Very very very very very Bad Man", "288"},
|
|
{"B", "The Very very Bad Man", "120"},
|
|
}
|
|
table.AppendBulk(dataWithlongText2)
|
|
table.SetAutoMergeCells(true)
|
|
table.SetRowLine(true)
|
|
table.Render()
|
|
want = `+------+--------------------------------+--------+
|
|
| NAME | SIGN | RATING |
|
|
+------+--------------------------------+--------+
|
|
| A | The Good | 500 |
|
|
+ +--------------------------------+--------+
|
|
| | The Very very very very very | 288 |
|
|
| | Bad Man | |
|
|
+------+--------------------------------+--------+
|
|
| B | The Very very Bad Man | 120 |
|
|
+------+--------------------------------+--------+
|
|
`
|
|
checkEqual(t, buf.String(), want)
|
|
}
|
|
|
|
func TestClearRows(t *testing.T) {
|
|
data := [][]string{
|
|
{"1/1/2014", "Domain name", "2233", "$10.98"},
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
table := NewWriter(&buf)
|
|
table.SetAutoWrapText(false)
|
|
table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
|
|
table.SetFooter([]string{"", "", "Total", "$145.93"}) // Add Footer
|
|
table.AppendBulk(data) // Add Bulk Data
|
|
table.Render()
|
|
|
|
originalWant := `+----------+-------------+-------+---------+
|
|
| DATE | DESCRIPTION | CV2 | AMOUNT |
|
|
+----------+-------------+-------+---------+
|
|
| 1/1/2014 | Domain name | 2233 | $10.98 |
|
|
+----------+-------------+-------+---------+
|
|
| TOTAL | $145.93 |
|
|
+----------+-------------+-------+---------+
|
|
`
|
|
want := originalWant
|
|
|
|
checkEqual(t, buf.String(), want, "table clear rows failed")
|
|
|
|
buf.Reset()
|
|
table.ClearRows()
|
|
table.Render()
|
|
|
|
want = `+----------+-------------+-------+---------+
|
|
| DATE | DESCRIPTION | CV2 | AMOUNT |
|
|
+----------+-------------+-------+---------+
|
|
+----------+-------------+-------+---------+
|
|
| TOTAL | $145.93 |
|
|
+----------+-------------+-------+---------+
|
|
`
|
|
|
|
checkEqual(t, buf.String(), want, "table clear rows failed")
|
|
|
|
buf.Reset()
|
|
table.AppendBulk(data) // Add Bulk Data
|
|
table.Render()
|
|
|
|
want = `+----------+-------------+-------+---------+
|
|
| DATE | DESCRIPTION | CV2 | AMOUNT |
|
|
+----------+-------------+-------+---------+
|
|
| 1/1/2014 | Domain name | 2233 | $10.98 |
|
|
+----------+-------------+-------+---------+
|
|
| TOTAL | $145.93 |
|
|
+----------+-------------+-------+---------+
|
|
`
|
|
|
|
checkEqual(t, buf.String(), want, "table clear rows failed")
|
|
}
|
|
|
|
func TestClearFooters(t *testing.T) {
|
|
data := [][]string{
|
|
{"1/1/2014", "Domain name", "2233", "$10.98"},
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
table := NewWriter(&buf)
|
|
table.SetAutoWrapText(false)
|
|
table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
|
|
table.SetFooter([]string{"", "", "Total", "$145.93"}) // Add Footer
|
|
table.AppendBulk(data) // Add Bulk Data
|
|
table.Render()
|
|
|
|
buf.Reset()
|
|
table.ClearFooter()
|
|
table.Render()
|
|
|
|
want := `+----------+-------------+-------+---------+
|
|
| DATE | DESCRIPTION | CV2 | AMOUNT |
|
|
+----------+-------------+-------+---------+
|
|
| 1/1/2014 | Domain name | 2233 | $10.98 |
|
|
+----------+-------------+-------+---------+
|
|
`
|
|
|
|
checkEqual(t, buf.String(), want)
|
|
}
|
|
|
|
func TestMoreDataColumnsThanHeaders(t *testing.T) {
|
|
var (
|
|
buf = &bytes.Buffer{}
|
|
table = NewWriter(buf)
|
|
header = []string{"A", "B", "C"}
|
|
data = [][]string{
|
|
{"a", "b", "c", "d"},
|
|
{"1", "2", "3", "4"},
|
|
}
|
|
want = `+---+---+---+---+
|
|
| A | B | C | |
|
|
+---+---+---+---+
|
|
| a | b | c | d |
|
|
| 1 | 2 | 3 | 4 |
|
|
+---+---+---+---+
|
|
`
|
|
)
|
|
table.SetHeader(header)
|
|
// table.SetFooter(ctx.tableCtx.footer)
|
|
table.AppendBulk(data)
|
|
table.Render()
|
|
|
|
checkEqual(t, buf.String(), want)
|
|
}
|
|
|
|
func TestMoreFooterColumnsThanHeaders(t *testing.T) {
|
|
var (
|
|
buf = &bytes.Buffer{}
|
|
table = NewWriter(buf)
|
|
header = []string{"A", "B", "C"}
|
|
data = [][]string{
|
|
{"a", "b", "c", "d"},
|
|
{"1", "2", "3", "4"},
|
|
}
|
|
footer = []string{"a", "b", "c", "d", "e"}
|
|
want = `+---+---+---+---+---+
|
|
| A | B | C | | |
|
|
+---+---+---+---+---+
|
|
| a | b | c | d |
|
|
| 1 | 2 | 3 | 4 |
|
|
+---+---+---+---+---+
|
|
| A | B | C | D | E |
|
|
+---+---+---+---+---+
|
|
`
|
|
)
|
|
table.SetHeader(header)
|
|
table.SetFooter(footer)
|
|
table.AppendBulk(data)
|
|
table.Render()
|
|
|
|
checkEqual(t, buf.String(), want)
|
|
}
|
|
|
|
func TestSetColMinWidth(t *testing.T) {
|
|
var (
|
|
buf = &bytes.Buffer{}
|
|
table = NewWriter(buf)
|
|
header = []string{"AAA", "BBB", "CCC"}
|
|
data = [][]string{
|
|
{"a", "b", "c"},
|
|
{"1", "2", "3"},
|
|
}
|
|
footer = []string{"a", "b", "cccc"}
|
|
want = `+-----+-----+-------+
|
|
| AAA | BBB | CCC |
|
|
+-----+-----+-------+
|
|
| a | b | c |
|
|
| 1 | 2 | 3 |
|
|
+-----+-----+-------+
|
|
| A | B | CCCC |
|
|
+-----+-----+-------+
|
|
`
|
|
)
|
|
table.SetHeader(header)
|
|
table.SetFooter(footer)
|
|
table.AppendBulk(data)
|
|
table.SetColMinWidth(2, 5)
|
|
table.Render()
|
|
|
|
checkEqual(t, buf.String(), want)
|
|
}
|
|
|
|
func TestWrapString(t *testing.T) {
|
|
want := []string{"ああああああああああああああああああああああああ", "あああああああ"}
|
|
got, _ := WrapString("ああああああああああああああああああああああああ あああああああ", 55)
|
|
checkEqual(t, got, want)
|
|
}
|
|
|
|
func TestNumberAlign(t *testing.T) {
|
|
var (
|
|
buf = &bytes.Buffer{}
|
|
table = NewWriter(buf)
|
|
data = [][]string{
|
|
{"AAAAAAAAAAAAA", "BBBBBBBBBBBBB", "CCCCCCCCCCCCCC"},
|
|
{"A", "B", "C"},
|
|
{"123456789", "2", "3"},
|
|
{"1", "2", "123,456,789"},
|
|
{"1", "123,456.789", "3"},
|
|
{"-123,456", "-2", "-3"},
|
|
}
|
|
want = `+---------------+---------------+----------------+
|
|
| AAAAAAAAAAAAA | BBBBBBBBBBBBB | CCCCCCCCCCCCCC |
|
|
| A | B | C |
|
|
| 123456789 | 2 | 3 |
|
|
| 1 | 2 | 123,456,789 |
|
|
| 1 | 123,456.789 | 3 |
|
|
| -123,456 | -2 | -3 |
|
|
+---------------+---------------+----------------+
|
|
`
|
|
)
|
|
table.AppendBulk(data)
|
|
table.Render()
|
|
|
|
checkEqual(t, buf.String(), want)
|
|
}
|
|
|
|
func TestCustomAlign(t *testing.T) {
|
|
var (
|
|
buf = &bytes.Buffer{}
|
|
table = NewWriter(buf)
|
|
header = []string{"AAA", "BBB", "CCC"}
|
|
data = [][]string{
|
|
{"a", "b", "c"},
|
|
{"1", "2", "3"},
|
|
}
|
|
footer = []string{"a", "b", "cccc"}
|
|
want = `+-----+-----+-------+
|
|
| AAA | BBB | CCC |
|
|
+-----+-----+-------+
|
|
| a | b | c |
|
|
| 1 | 2 | 3 |
|
|
+-----+-----+-------+
|
|
| A | B | CCCC |
|
|
+-----+-----+-------+
|
|
`
|
|
)
|
|
table.SetHeader(header)
|
|
table.SetFooter(footer)
|
|
table.AppendBulk(data)
|
|
table.SetColMinWidth(2, 5)
|
|
table.SetColumnAlignment([]int{ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT})
|
|
table.Render()
|
|
|
|
checkEqual(t, buf.String(), want)
|
|
}
|
|
|
|
func TestTitle(t *testing.T) {
|
|
ts := []struct {
|
|
text string
|
|
want string
|
|
}{
|
|
{"", ""},
|
|
{"foo", "FOO"},
|
|
{"Foo", "FOO"},
|
|
{"foO", "FOO"},
|
|
{".foo", "FOO"},
|
|
{"foo.", "FOO"},
|
|
{".foo.", "FOO"},
|
|
{".foo.bar.", "FOO BAR"},
|
|
{"_foo", "FOO"},
|
|
{"foo_", "FOO"},
|
|
{"_foo_", "FOO"},
|
|
{"_foo_bar_", "FOO BAR"},
|
|
{" foo", "FOO"},
|
|
{"foo ", "FOO"},
|
|
{" foo ", "FOO"},
|
|
{" foo bar ", "FOO BAR"},
|
|
{"0.1", "0.1"},
|
|
{"FOO 0.1", "FOO 0.1"},
|
|
{".1 0.1", ".1 0.1"},
|
|
{"1. 0.1", "1. 0.1"},
|
|
{"1. 0.", "1. 0."},
|
|
{".1. 0.", ".1. 0."},
|
|
{".$ . $.", "$ . $"},
|
|
{".$. $.", "$ $"},
|
|
}
|
|
for _, tt := range ts {
|
|
got := Title(tt.text)
|
|
if got != tt.want {
|
|
t.Errorf("want %q, bot got %q", tt.want, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestKubeFormat(t *testing.T) {
|
|
data := [][]string{
|
|
{"1/1/2014", "jan_hosting", "2233", "$10.98"},
|
|
{"1/1/2014", "feb_hosting", "2233", "$54.95"},
|
|
{"1/4/2014", "feb_extra_bandwidth", "2233", "$51.00"},
|
|
{"1/4/2014", "mar_hosting", "2233", "$30.00"},
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
table := NewWriter(&buf)
|
|
table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
|
|
table.SetAutoWrapText(false)
|
|
table.SetAutoFormatHeaders(true)
|
|
table.SetHeaderAlignment(ALIGN_LEFT)
|
|
table.SetAlignment(ALIGN_LEFT)
|
|
table.SetCenterSeparator("")
|
|
table.SetColumnSeparator("")
|
|
table.SetRowSeparator("")
|
|
table.SetHeaderLine(false)
|
|
table.SetBorder(false)
|
|
table.SetTablePadding("\t") // pad with tabs
|
|
table.SetNoWhiteSpace(true)
|
|
table.AppendBulk(data) // Add Bulk Data
|
|
table.Render()
|
|
|
|
want := `DATE DESCRIPTION CV2 AMOUNT
|
|
1/1/2014 jan_hosting 2233 $10.98
|
|
1/1/2014 feb_hosting 2233 $54.95
|
|
1/4/2014 feb_extra_bandwidth 2233 $51.00
|
|
1/4/2014 mar_hosting 2233 $30.00
|
|
`
|
|
|
|
checkEqual(t, buf.String(), want, "kube format rendering failed")
|
|
}
|