github.com/cli/cli@v1.14.1-0.20210902173923-1af6a669e342/pkg/cmdutil/json_flags_test.go (about)

     1  package cmdutil
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"testing"
     8  
     9  	"github.com/cli/cli/pkg/iostreams"
    10  	"github.com/spf13/cobra"
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  func TestAddJSONFlags(t *testing.T) {
    16  	tests := []struct {
    17  		name        string
    18  		fields      []string
    19  		args        []string
    20  		wantsExport *exportFormat
    21  		wantsError  string
    22  	}{
    23  		{
    24  			name:        "no JSON flag",
    25  			fields:      []string{},
    26  			args:        []string{},
    27  			wantsExport: nil,
    28  		},
    29  		{
    30  			name:        "empty JSON flag",
    31  			fields:      []string{"one", "two"},
    32  			args:        []string{"--json"},
    33  			wantsExport: nil,
    34  			wantsError:  "Specify one or more comma-separated fields for `--json`:\n  one\n  two",
    35  		},
    36  		{
    37  			name:        "invalid JSON field",
    38  			fields:      []string{"id", "number"},
    39  			args:        []string{"--json", "idontexist"},
    40  			wantsExport: nil,
    41  			wantsError:  "Unknown JSON field: \"idontexist\"\nAvailable fields:\n  id\n  number",
    42  		},
    43  		{
    44  			name:        "cannot combine --json with --web",
    45  			fields:      []string{"id", "number", "title"},
    46  			args:        []string{"--json", "id", "--web"},
    47  			wantsExport: nil,
    48  			wantsError:  "cannot use `--web` with `--json`",
    49  		},
    50  		{
    51  			name:        "cannot use --jq without --json",
    52  			fields:      []string{},
    53  			args:        []string{"--jq", ".number"},
    54  			wantsExport: nil,
    55  			wantsError:  "cannot use `--jq` without specifying `--json`",
    56  		},
    57  		{
    58  			name:        "cannot use --template without --json",
    59  			fields:      []string{},
    60  			args:        []string{"--template", "{{.number}}"},
    61  			wantsExport: nil,
    62  			wantsError:  "cannot use `--template` without specifying `--json`",
    63  		},
    64  		{
    65  			name:   "with JSON fields",
    66  			fields: []string{"id", "number", "title"},
    67  			args:   []string{"--json", "number,title"},
    68  			wantsExport: &exportFormat{
    69  				fields:   []string{"number", "title"},
    70  				filter:   "",
    71  				template: "",
    72  			},
    73  		},
    74  		{
    75  			name:   "with jq filter",
    76  			fields: []string{"id", "number", "title"},
    77  			args:   []string{"--json", "number", "-q.number"},
    78  			wantsExport: &exportFormat{
    79  				fields:   []string{"number"},
    80  				filter:   ".number",
    81  				template: "",
    82  			},
    83  		},
    84  		{
    85  			name:   "with Go template",
    86  			fields: []string{"id", "number", "title"},
    87  			args:   []string{"--json", "number", "-t", "{{.number}}"},
    88  			wantsExport: &exportFormat{
    89  				fields:   []string{"number"},
    90  				filter:   "",
    91  				template: "{{.number}}",
    92  			},
    93  		},
    94  	}
    95  	for _, tt := range tests {
    96  		t.Run(tt.name, func(t *testing.T) {
    97  			cmd := &cobra.Command{Run: func(*cobra.Command, []string) {}}
    98  			cmd.Flags().Bool("web", false, "")
    99  			var exporter Exporter
   100  			AddJSONFlags(cmd, &exporter, tt.fields)
   101  			cmd.SetArgs(tt.args)
   102  			cmd.SetOut(ioutil.Discard)
   103  			cmd.SetErr(ioutil.Discard)
   104  			_, err := cmd.ExecuteC()
   105  			if tt.wantsError == "" {
   106  				require.NoError(t, err)
   107  			} else {
   108  				assert.EqualError(t, err, tt.wantsError)
   109  				return
   110  			}
   111  			if tt.wantsExport == nil {
   112  				assert.Nil(t, exporter)
   113  			} else {
   114  				assert.Equal(t, tt.wantsExport, exporter)
   115  			}
   116  		})
   117  	}
   118  }
   119  
   120  func Test_exportFormat_Write(t *testing.T) {
   121  	type args struct {
   122  		data interface{}
   123  	}
   124  	tests := []struct {
   125  		name     string
   126  		exporter exportFormat
   127  		args     args
   128  		wantW    string
   129  		wantErr  bool
   130  	}{
   131  		{
   132  			name:     "regular JSON output",
   133  			exporter: exportFormat{},
   134  			args: args{
   135  				data: map[string]string{"name": "hubot"},
   136  			},
   137  			wantW:   "{\"name\":\"hubot\"}\n",
   138  			wantErr: false,
   139  		},
   140  		{
   141  			name:     "call ExportData",
   142  			exporter: exportFormat{fields: []string{"field1", "field2"}},
   143  			args: args{
   144  				data: &exportableItem{"item1"},
   145  			},
   146  			wantW:   "{\"field1\":\"item1:field1\",\"field2\":\"item1:field2\"}\n",
   147  			wantErr: false,
   148  		},
   149  		{
   150  			name:     "recursively call ExportData",
   151  			exporter: exportFormat{fields: []string{"f1", "f2"}},
   152  			args: args{
   153  				data: map[string]interface{}{
   154  					"s1": []exportableItem{{"i1"}, {"i2"}},
   155  					"s2": []exportableItem{{"i3"}},
   156  				},
   157  			},
   158  			wantW:   "{\"s1\":[{\"f1\":\"i1:f1\",\"f2\":\"i1:f2\"},{\"f1\":\"i2:f1\",\"f2\":\"i2:f2\"}],\"s2\":[{\"f1\":\"i3:f1\",\"f2\":\"i3:f2\"}]}\n",
   159  			wantErr: false,
   160  		},
   161  		{
   162  			name:     "with jq filter",
   163  			exporter: exportFormat{filter: ".name"},
   164  			args: args{
   165  				data: map[string]string{"name": "hubot"},
   166  			},
   167  			wantW:   "hubot\n",
   168  			wantErr: false,
   169  		},
   170  		{
   171  			name:     "with Go template",
   172  			exporter: exportFormat{template: "{{.name}}"},
   173  			args: args{
   174  				data: map[string]string{"name": "hubot"},
   175  			},
   176  			wantW:   "hubot",
   177  			wantErr: false,
   178  		},
   179  	}
   180  	for _, tt := range tests {
   181  		t.Run(tt.name, func(t *testing.T) {
   182  			w := &bytes.Buffer{}
   183  			io := &iostreams.IOStreams{
   184  				Out: w,
   185  			}
   186  			if err := tt.exporter.Write(io, tt.args.data); (err != nil) != tt.wantErr {
   187  				t.Errorf("exportFormat.Write() error = %v, wantErr %v", err, tt.wantErr)
   188  				return
   189  			}
   190  			if gotW := w.String(); gotW != tt.wantW {
   191  				t.Errorf("exportFormat.Write() = %q, want %q", gotW, tt.wantW)
   192  			}
   193  		})
   194  	}
   195  }
   196  
   197  type exportableItem struct {
   198  	Name string
   199  }
   200  
   201  func (e *exportableItem) ExportData(fields []string) *map[string]interface{} {
   202  	m := map[string]interface{}{}
   203  	for _, f := range fields {
   204  		m[f] = fmt.Sprintf("%s:%s", e.Name, f)
   205  	}
   206  	return &m
   207  }