github.com/xeptore/docker-cli@v20.10.14+incompatible/cli/command/registry/formatter_search_test.go (about)

     1  package registry
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"strings"
     7  	"testing"
     8  
     9  	"github.com/docker/cli/cli/command/formatter"
    10  	"github.com/docker/cli/internal/test"
    11  	registrytypes "github.com/docker/docker/api/types/registry"
    12  	"gotest.tools/v3/assert"
    13  	is "gotest.tools/v3/assert/cmp"
    14  	"gotest.tools/v3/golden"
    15  )
    16  
    17  func TestSearchContext(t *testing.T) {
    18  	name := "nginx"
    19  	starCount := 5000
    20  
    21  	var ctx searchContext
    22  	cases := []struct {
    23  		searchCtx searchContext
    24  		expValue  string
    25  		call      func() string
    26  	}{
    27  		{searchContext{
    28  			s: registrytypes.SearchResult{Name: name},
    29  		}, name, ctx.Name},
    30  		{searchContext{
    31  			s: registrytypes.SearchResult{StarCount: starCount},
    32  		}, "5000", ctx.StarCount},
    33  		{searchContext{
    34  			s: registrytypes.SearchResult{IsOfficial: true},
    35  		}, "[OK]", ctx.IsOfficial},
    36  		{searchContext{
    37  			s: registrytypes.SearchResult{IsOfficial: false},
    38  		}, "", ctx.IsOfficial},
    39  		{searchContext{
    40  			s: registrytypes.SearchResult{IsAutomated: true},
    41  		}, "[OK]", ctx.IsAutomated},
    42  		{searchContext{
    43  			s: registrytypes.SearchResult{IsAutomated: false},
    44  		}, "", ctx.IsAutomated},
    45  	}
    46  
    47  	for _, c := range cases {
    48  		ctx = c.searchCtx
    49  		v := c.call()
    50  		if strings.Contains(v, ",") {
    51  			test.CompareMultipleValues(t, v, c.expValue)
    52  		} else if v != c.expValue {
    53  			t.Fatalf("Expected %s, was %s\n", c.expValue, v)
    54  		}
    55  	}
    56  }
    57  
    58  func TestSearchContextDescription(t *testing.T) {
    59  	shortDescription := "Official build of Nginx."
    60  	longDescription := "Automated Nginx reverse proxy for docker containers"
    61  	descriptionWReturns := "Automated\nNginx reverse\rproxy\rfor docker\ncontainers"
    62  
    63  	var ctx searchContext
    64  	cases := []struct {
    65  		searchCtx searchContext
    66  		expValue  string
    67  		call      func() string
    68  	}{
    69  		{searchContext{
    70  			s:     registrytypes.SearchResult{Description: shortDescription},
    71  			trunc: true,
    72  		}, shortDescription, ctx.Description},
    73  		{searchContext{
    74  			s:     registrytypes.SearchResult{Description: shortDescription},
    75  			trunc: false,
    76  		}, shortDescription, ctx.Description},
    77  		{searchContext{
    78  			s:     registrytypes.SearchResult{Description: longDescription},
    79  			trunc: false,
    80  		}, longDescription, ctx.Description},
    81  		{searchContext{
    82  			s:     registrytypes.SearchResult{Description: longDescription},
    83  			trunc: true,
    84  		}, formatter.Ellipsis(longDescription, 45), ctx.Description},
    85  		{searchContext{
    86  			s:     registrytypes.SearchResult{Description: descriptionWReturns},
    87  			trunc: false,
    88  		}, longDescription, ctx.Description},
    89  		{searchContext{
    90  			s:     registrytypes.SearchResult{Description: descriptionWReturns},
    91  			trunc: true,
    92  		}, formatter.Ellipsis(longDescription, 45), ctx.Description},
    93  	}
    94  
    95  	for _, c := range cases {
    96  		ctx = c.searchCtx
    97  		v := c.call()
    98  		if strings.Contains(v, ",") {
    99  			test.CompareMultipleValues(t, v, c.expValue)
   100  		} else if v != c.expValue {
   101  			t.Fatalf("Expected %s, was %s\n", c.expValue, v)
   102  		}
   103  	}
   104  }
   105  
   106  func TestSearchContextWrite(t *testing.T) {
   107  	cases := []struct {
   108  		context  formatter.Context
   109  		expected string
   110  	}{
   111  
   112  		// Errors
   113  		{
   114  			formatter.Context{Format: "{{InvalidFunction}}"},
   115  			`Template parsing error: template: :1: function "InvalidFunction" not defined
   116  `,
   117  		},
   118  		{
   119  			formatter.Context{Format: "{{nil}}"},
   120  			`Template parsing error: template: :1:2: executing "" at <nil>: nil is not a command
   121  `,
   122  		},
   123  		// Table format
   124  		{
   125  			formatter.Context{Format: NewSearchFormat("table")},
   126  			string(golden.Get(t, "search-context-write-table.golden")),
   127  		},
   128  		{
   129  			formatter.Context{Format: NewSearchFormat("table {{.Name}}")},
   130  			`NAME
   131  result1
   132  result2
   133  `,
   134  		},
   135  		// Custom Format
   136  		{
   137  			formatter.Context{Format: NewSearchFormat("{{.Name}}")},
   138  			`result1
   139  result2
   140  `,
   141  		},
   142  		// Custom Format with CreatedAt
   143  		{
   144  			formatter.Context{Format: NewSearchFormat("{{.Name}} {{.StarCount}}")},
   145  			`result1 5000
   146  result2 5
   147  `,
   148  		},
   149  	}
   150  
   151  	results := []registrytypes.SearchResult{
   152  		{Name: "result1", Description: "Official build", StarCount: 5000, IsOfficial: true, IsAutomated: false},
   153  		{Name: "result2", Description: "Not official", StarCount: 5, IsOfficial: false, IsAutomated: true},
   154  	}
   155  
   156  	for _, tc := range cases {
   157  		tc := tc
   158  		t.Run(string(tc.context.Format), func(t *testing.T) {
   159  			var out bytes.Buffer
   160  			tc.context.Output = &out
   161  
   162  			err := SearchWrite(tc.context, results)
   163  			if err != nil {
   164  				assert.Error(t, err, tc.expected)
   165  			} else {
   166  				assert.Equal(t, out.String(), tc.expected)
   167  			}
   168  		})
   169  	}
   170  }
   171  
   172  func TestSearchContextWriteJSON(t *testing.T) {
   173  	results := []registrytypes.SearchResult{
   174  		{Name: "result1", Description: "Official build", StarCount: 5000, IsOfficial: true, IsAutomated: false},
   175  		{Name: "result2", Description: "Not official", StarCount: 5, IsOfficial: false, IsAutomated: true},
   176  	}
   177  	expectedJSONs := []map[string]interface{}{
   178  		{"Name": "result1", "Description": "Official build", "StarCount": "5000", "IsOfficial": "true", "IsAutomated": "false"},
   179  		{"Name": "result2", "Description": "Not official", "StarCount": "5", "IsOfficial": "false", "IsAutomated": "true"},
   180  	}
   181  
   182  	out := bytes.NewBufferString("")
   183  	err := SearchWrite(formatter.Context{Format: "{{json .}}", Output: out}, results)
   184  	if err != nil {
   185  		t.Fatal(err)
   186  	}
   187  	for i, line := range strings.Split(strings.TrimSpace(out.String()), "\n") {
   188  		t.Logf("Output: line %d: %s", i, line)
   189  		var m map[string]interface{}
   190  		if err := json.Unmarshal([]byte(line), &m); err != nil {
   191  			t.Fatal(err)
   192  		}
   193  		assert.Check(t, is.DeepEqual(m, expectedJSONs[i]))
   194  	}
   195  }
   196  
   197  func TestSearchContextWriteJSONField(t *testing.T) {
   198  	results := []registrytypes.SearchResult{
   199  		{Name: "result1", Description: "Official build", StarCount: 5000, IsOfficial: true, IsAutomated: false},
   200  		{Name: "result2", Description: "Not official", StarCount: 5, IsOfficial: false, IsAutomated: true},
   201  	}
   202  	out := bytes.NewBufferString("")
   203  	err := SearchWrite(formatter.Context{Format: "{{json .Name}}", Output: out}, results)
   204  	if err != nil {
   205  		t.Fatal(err)
   206  	}
   207  	for i, line := range strings.Split(strings.TrimSpace(out.String()), "\n") {
   208  		t.Logf("Output: line %d: %s", i, line)
   209  		var s string
   210  		if err := json.Unmarshal([]byte(line), &s); err != nil {
   211  			t.Fatal(err)
   212  		}
   213  		assert.Check(t, is.Equal(s, results[i].Name))
   214  	}
   215  }