github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/internal/table/table_test.go (about)

     1  package table
     2  
     3  import (
     4  	"reflect"
     5  	"strings"
     6  	"testing"
     7  
     8  	"github.com/ActiveState/cli/internal/mathutils"
     9  	"github.com/stretchr/testify/assert"
    10  )
    11  
    12  func TestTable_colWidths(t1 *testing.T) {
    13  	type args struct {
    14  		table         *Table
    15  		maxTotalWidth int
    16  	}
    17  	tests := []struct {
    18  		name string
    19  		args args
    20  		want []int
    21  	}{
    22  		{
    23  			"Under max total",
    24  			args{
    25  				&Table{
    26  					[]string{"123", "1234", "12345"},
    27  					[]row{
    28  						{[]string{"1", "2", "3"}},
    29  					},
    30  					false,
    31  					false,
    32  					false,
    33  				},
    34  				100,
    35  			},
    36  			[]int{7, 8, 9},
    37  		},
    38  		{
    39  			"multi-byte characters",
    40  			args{
    41  				&Table{
    42  					[]string{"12✔", "1234", "12345"},
    43  					[]row{
    44  						{[]string{"1", "2", "3"}},
    45  					},
    46  					false,
    47  					false,
    48  					false,
    49  				},
    50  				100,
    51  			},
    52  			[]int{7, 8, 9},
    53  		},
    54  		{
    55  			"span row dominates",
    56  			args{
    57  				&Table{
    58  					[]string{"123", "1234", "12345"},
    59  					[]row{
    60  						{[]string{"1", "2", "3"}},
    61  						{[]string{"1", "0123456789012345678901234567890123456789"}},
    62  					},
    63  					false,
    64  					false,
    65  					false,
    66  				},
    67  				100,
    68  			},
    69  			[]int{14, 17, 20},
    70  		},
    71  		{
    72  			"Rowsize wins cause it's longer",
    73  			args{
    74  				&Table{
    75  					[]string{"1", "2", "3"},
    76  					[]row{
    77  						{[]string{"123", "1234", "12345"}},
    78  					},
    79  					false,
    80  					false,
    81  					false,
    82  				},
    83  				100,
    84  			},
    85  			[]int{7, 8, 9},
    86  		},
    87  		{
    88  			"Over max total",
    89  			args{
    90  				&Table{
    91  					[]string{strings.Repeat("-", 40), strings.Repeat("-", 50), strings.Repeat("-", 60)},
    92  					[]row{
    93  						{[]string{"1", "2", "3"}},
    94  					},
    95  					false,
    96  					false,
    97  					false,
    98  				},
    99  				100,
   100  			},
   101  			[]int{28, 33, 39},
   102  		},
   103  		{
   104  			"Long multi column",
   105  			args{
   106  				&Table{
   107  					[]string{"a", "b", "c", "d"},
   108  					[]row{
   109  						{[]string{"1", "1", "12", "12"}},
   110  						{[]string{strings.Repeat(" ", 100)}},
   111  					},
   112  					false,
   113  					false,
   114  					false,
   115  				},
   116  				100,
   117  			},
   118  			[]int{22, 22, 27, 29},
   119  		},
   120  		{
   121  			"Long multi column (over maxWidth)",
   122  			args{
   123  				&Table{
   124  					[]string{"a", "b", "c", "d"},
   125  					[]row{
   126  						{[]string{"1", "1", "12", "12"}},
   127  						{[]string{"1", strings.Repeat(" ", 200)}},
   128  					},
   129  					false,
   130  					false,
   131  					false,
   132  				},
   133  				100,
   134  			},
   135  			[]int{22, 22, 27, 29},
   136  		},
   137  	}
   138  	for _, tt := range tests {
   139  		t1.Run(tt.name, func(t1 *testing.T) {
   140  			got, total := tt.args.table.calculateWidth(tt.args.maxTotalWidth)
   141  			if !reflect.DeepEqual(got, tt.want) {
   142  				t1.Errorf("calculateWidth() = %v, want %v", got, tt.want)
   143  			}
   144  
   145  			assert.LessOrEqual(t1, total, tt.args.maxTotalWidth)
   146  		})
   147  	}
   148  }
   149  
   150  func Test_renderRow(t *testing.T) {
   151  	type args struct {
   152  		providedColumns []string
   153  		colWidths       []int
   154  	}
   155  	tests := []struct {
   156  		name string
   157  		args args
   158  		want string
   159  	}{
   160  		{
   161  			"No breaks",
   162  			args{
   163  				providedColumns: []string{"col1", "col2", "col3"},
   164  				colWidths:       []int{10, 10, 10},
   165  			},
   166  			"  col1      col2      col3    ",
   167  		},
   168  		{
   169  			"No breaks with color codes",
   170  			args{
   171  				providedColumns: []string{"[HEADING]col1[/RESET]", "[HEADING]col2[/RESET]", "[HEADING]col3[/RESET]"},
   172  				colWidths:       []int{10, 10, 10},
   173  			},
   174  			"  [HEADING]col1[/RESET]      [HEADING]col2[/RESET]      [HEADING]col3[/RESET]    ",
   175  		},
   176  		{
   177  			"Breaks",
   178  			args{
   179  				providedColumns: []string{"col1", "col2", "col3"},
   180  				colWidths:       []int{6, 6, 6},
   181  			},
   182  			"  co    co    co  \n" +
   183  				"  l1    l2    l3  ",
   184  		},
   185  		{
   186  			"Breaks with color codes",
   187  			args{
   188  				providedColumns: []string{"[HEADING]col1[/RESET]", "[HEADING]col2[/RESET]", "[HEADING]col3[/RESET]"},
   189  				colWidths:       []int{6, 6, 6},
   190  			},
   191  			"  [HEADING]co    [HEADING]co    [HEADING]co  \n" +
   192  				"  l1[/RESET]    l2[/RESET]    l3[/RESET]  ",
   193  		},
   194  		{
   195  			"Breaks for multi-byte characters",
   196  			args{
   197  				providedColumns: []string{"✔ol1", "✔ol2", "✔ol3"},
   198  				colWidths:       []int{6, 6, 6},
   199  			},
   200  			"  ✔o    ✔o    ✔o  \n" +
   201  				"  l1    l2    l3  ",
   202  		},
   203  		{
   204  			"Empty column",
   205  			args{
   206  				providedColumns: []string{"col1", "", "col3"},
   207  				colWidths:       []int{6, 6, 6},
   208  			},
   209  			"  co          co  \n" +
   210  				"  l1          l3  ",
   211  		},
   212  		{
   213  			"Mutli column span",
   214  			args{
   215  				providedColumns: []string{"abcdefgh", "jklmnopqrstu"},
   216  				colWidths:       []int{6, 6, 6},
   217  			},
   218  			"  ab    jklmnopq  \n" +
   219  				"  cd    rstu      \n" +
   220  				"  ef              \n" +
   221  				"  gh              ",
   222  		},
   223  		{
   224  			"Single row mutli column span",
   225  			args{
   226  				providedColumns: []string{"123456789"},
   227  				colWidths:       []int{1, 2, 3, 4, 5},
   228  			},
   229  			"  123456789    ",
   230  		},
   231  		{
   232  			"Multi line second column",
   233  			args{
   234  				providedColumns: []string{"abcd", "abcdefgh"},
   235  				colWidths:       []int{8, 8},
   236  			},
   237  			"  abcd    abcd  \n" +
   238  				"          efgh  ",
   239  		},
   240  		{
   241  			"Multi line second column with line breaks",
   242  			args{
   243  				providedColumns: []string{"abcd", "abcde\nfgh"},
   244  				colWidths:       []int{8, 8},
   245  			},
   246  			"  abcd    abcd  \n" +
   247  				"          e     \n" +
   248  				"          fgh   ",
   249  		},
   250  	}
   251  	for _, tt := range tests {
   252  		t.Run(tt.name, func(t *testing.T) {
   253  			if got := renderRow(tt.args.providedColumns, tt.args.colWidths); got != tt.want {
   254  				t.Errorf("renderRow() = '%v', want '%v'", renderBreaks(got), renderBreaks(tt.want))
   255  			}
   256  		})
   257  	}
   258  }
   259  
   260  func renderBreaks(v string) string {
   261  	return strings.ReplaceAll(v, "\n", `\n`)
   262  }
   263  
   264  func Test_equalizeWidths(t *testing.T) {
   265  	type args struct {
   266  		colWidths  []int
   267  		percentage int
   268  	}
   269  	tests := []struct {
   270  		name string
   271  		args args
   272  		want []int
   273  	}{
   274  		{
   275  			"Equalize widths",
   276  			args{
   277  				[]int{10, 20, 30},
   278  				20,
   279  			},
   280  			[]int{12, 20, 28},
   281  		},
   282  		{
   283  			"Equalize widths, account for floats",
   284  			args{
   285  				[]int{1, 1, 5},
   286  				40,
   287  			},
   288  			[]int{1, 1, 5},
   289  		},
   290  		{
   291  			"Zero percentage doesn't panic or break",
   292  			args{
   293  				[]int{11, 21, 31},
   294  				0,
   295  			},
   296  			[]int{11, 21, 31},
   297  		},
   298  	}
   299  	for _, tt := range tests {
   300  		t.Run(tt.name, func(t *testing.T) {
   301  			originalTotal := mathutils.Total(tt.args.colWidths...)
   302  			equalizeWidths(tt.args.colWidths, tt.args.percentage)
   303  			if !reflect.DeepEqual(tt.args.colWidths, tt.want) {
   304  				t.Errorf("equalizeWidths() got = %v, want %v", tt.args.colWidths, tt.want)
   305  			}
   306  			if originalTotal != mathutils.Total(tt.args.colWidths...) {
   307  				t.Errorf("Output total should be equal to input total, got: %v", tt.args.colWidths)
   308  			}
   309  		})
   310  	}
   311  }
   312  
   313  func Test_rescaleColumns(t *testing.T) {
   314  	type args struct {
   315  		colWidths   []int
   316  		targetTotal int
   317  	}
   318  	tests := []struct {
   319  		name string
   320  		args args
   321  		want []int
   322  	}{
   323  		{
   324  			"Rescale widths, bigger",
   325  			args{
   326  				[]int{5, 5, 5},
   327  				20,
   328  			},
   329  			[]int{6, 6, 8},
   330  		},
   331  		{
   332  			"Rescale widths, same",
   333  			args{
   334  				[]int{5, 5, 5},
   335  				15,
   336  			},
   337  			[]int{5, 5, 5},
   338  		},
   339  		{
   340  			"Rescale widths, smaller",
   341  			args{
   342  				[]int{5, 5, 5},
   343  				10,
   344  			},
   345  			[]int{3, 3, 4},
   346  		},
   347  	}
   348  	for _, tt := range tests {
   349  		t.Run(tt.name, func(t *testing.T) {
   350  			rescaleColumns(tt.args.colWidths, tt.args.targetTotal, false, tt.args.colWidths[0])
   351  			if !reflect.DeepEqual(tt.args.colWidths, tt.want) {
   352  				t.Errorf("rescaleColumns() got = %v, want %v", tt.args.colWidths, tt.want)
   353  			}
   354  			total := mathutils.Total(tt.args.colWidths...)
   355  			if tt.args.targetTotal != total {
   356  				t.Errorf("rescaleColumns() got total = %v, want total %v", total, tt.args.targetTotal)
   357  			}
   358  		})
   359  	}
   360  }