github.com/opentelekomcloud/gophertelekomcloud@v0.9.3/internal/extract/json_test.go (about)

     1  package extract
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"math/rand"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  // randomString duplicates here to avoid cyclic imports
    15  // TODO: this function should be moved to some other package later
    16  func randomString(prefix string, n int) string {
    17  	const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
    18  	var bytes = make([]byte, n)
    19  	_, _ = rand.Read(bytes)
    20  	for i, b := range bytes {
    21  		bytes[i] = alphanum[b%byte(len(alphanum))]
    22  	}
    23  	return prefix + string(bytes)
    24  }
    25  
    26  type localCloser struct {
    27  	*bytes.Reader
    28  
    29  	closed bool
    30  }
    31  
    32  func (lc *localCloser) Close() error {
    33  	lc.closed = true
    34  	return nil
    35  }
    36  
    37  func TestInto(t *testing.T) {
    38  	key := "data_key"
    39  	value := randomString("v-", 20)
    40  
    41  	expected := map[string]string{key: value}
    42  
    43  	t.Run("io.Reader", func(t *testing.T) {
    44  		t.Parallel()
    45  
    46  		data := bytes.NewReader([]byte(fmt.Sprintf(`{ "data_key":  "%s"}`, value)))
    47  
    48  		actual := make(map[string]string)
    49  		err := Into(data, &actual)
    50  
    51  		assert.NoError(t, err) // not exiting after one fail
    52  		assert.EqualValues(t, expected[key], actual[key])
    53  	})
    54  
    55  	t.Run("io.ReadCloser", func(t *testing.T) {
    56  		t.Parallel()
    57  
    58  		data := bytes.NewReader([]byte(fmt.Sprintf(`{ "data_key":  "%s"}`, value)))
    59  		closer := &localCloser{Reader: data}
    60  
    61  		actual := make(map[string]string)
    62  		err := Into(closer, &actual)
    63  
    64  		assert.NoError(t, err) // not exiting after one fail
    65  		assert.EqualValues(t, expected[key], actual[key])
    66  		assert.True(t, closer.closed)
    67  	})
    68  }
    69  
    70  type TestDataType struct {
    71  	DataKey string `json:"data_key"`
    72  }
    73  
    74  type TestDataType2 struct {
    75  	TestDataType
    76  
    77  	SecondDataField string `json:"second_data_field"`
    78  }
    79  
    80  func readerFromString(src string) io.Reader {
    81  	return bytes.NewReader([]byte(src))
    82  }
    83  
    84  func TestIntoStructPtr(t *testing.T) {
    85  	t.Run("ok", func(t *testing.T) {
    86  		t.Parallel()
    87  
    88  		actual := new(TestDataType)
    89  		value := randomString("v-", 20)
    90  
    91  		data := fmt.Sprintf(`
    92  		{
    93  			"data_key": "%s"
    94  		}
    95  		`, value)
    96  
    97  		err := IntoStructPtr(readerFromString(data), actual, "")
    98  		require.NoError(t, err)
    99  		require.Equal(t, value, actual.DataKey)
   100  	})
   101  
   102  	t.Run("with label", func(t *testing.T) {
   103  		t.Parallel()
   104  
   105  		actual := new(TestDataType)
   106  		value := randomString("v-", 20)
   107  
   108  		data := fmt.Sprintf(`
   109  		{
   110  			"internal": {
   111  				"data_key": "%s"
   112  			}
   113  		}
   114  		`, value)
   115  
   116  		err := IntoStructPtr(readerFromString(data), actual, "internal")
   117  		require.NoError(t, err)
   118  		require.Equal(t, value, actual.DataKey)
   119  	})
   120  
   121  	t.Run("with label and embed", func(t *testing.T) {
   122  		t.Parallel()
   123  
   124  		actual := new(TestDataType2)
   125  		value := randomString("v-", 20)
   126  
   127  		data := fmt.Sprintf(`
   128  		{
   129  			"internal": {
   130  				"data_key": "%s",
   131  				"second_data_field": "%[1]s-2"
   132  			}
   133  		}
   134  		`, value)
   135  
   136  		err := IntoStructPtr(readerFromString(data), actual, "internal")
   137  		require.NoError(t, err)
   138  		require.Equal(t, value, actual.DataKey)
   139  		require.Equal(t, value+"-2", actual.SecondDataField)
   140  	})
   141  
   142  	t.Run("with label (err)", func(t *testing.T) {
   143  		t.Parallel()
   144  
   145  		actual := new(TestDataType)
   146  		value := randomString("v-", 20)
   147  
   148  		data := fmt.Sprintf(`
   149  		{
   150  			"internal": {
   151  				"data_key": "%s"
   152  			}
   153  		}
   154  		`, value)
   155  
   156  		err := IntoStructPtr(readerFromString(data), actual, "")
   157  		require.NoError(t, err)
   158  		require.Equal(t, "", actual.DataKey)
   159  	})
   160  
   161  	t.Run("non pointer", func(t *testing.T) {
   162  		t.Parallel()
   163  
   164  		actual := TestDataType{}
   165  		value := randomString("v-", 20)
   166  
   167  		data := fmt.Sprintf(`
   168  		{
   169  			"data_key": "%s"
   170  		}
   171  		`, value)
   172  
   173  		err := IntoStructPtr(readerFromString(data), actual, "")
   174  		require.EqualError(t, err, "expected pointer, got struct")
   175  	})
   176  
   177  	t.Run("non struct", func(t *testing.T) {
   178  		t.Parallel()
   179  
   180  		actual := make(map[string]interface{})
   181  		value := randomString("v-", 20)
   182  
   183  		data := fmt.Sprintf(`
   184  		{
   185  			"data_key": "%s"
   186  		}
   187  		`, value)
   188  
   189  		err := IntoStructPtr(readerFromString(data), &actual, "")
   190  		require.EqualError(t, err, "expected pointer to struct, got: *map[string]interface {}")
   191  	})
   192  }
   193  
   194  func TestIntoSlicePtr(t *testing.T) {
   195  	t.Run("ok", func(t *testing.T) {
   196  		t.Parallel()
   197  
   198  		actual := make([]TestDataType, 0)
   199  		value := randomString("v-", 20)
   200  
   201  		data := fmt.Sprintf(`
   202  		[{
   203  			"data_key": "%s"
   204  		}]
   205  		`, value)
   206  
   207  		err := IntoSlicePtr(readerFromString(data), &actual, "")
   208  		require.NoError(t, err)
   209  		require.Len(t, actual, 1)
   210  		require.Equal(t, value, actual[0].DataKey)
   211  	})
   212  
   213  	t.Run("with label", func(t *testing.T) {
   214  		t.Parallel()
   215  
   216  		actual := make([]TestDataType, 0)
   217  		value := randomString("v-", 20)
   218  
   219  		data := fmt.Sprintf(`
   220  		{
   221  			"data": [{ "data_key": "%s" }]
   222  		}
   223  		`, value)
   224  
   225  		err := IntoSlicePtr(readerFromString(data), &actual, "data")
   226  		require.NoError(t, err)
   227  		require.Len(t, actual, 1)
   228  		require.Equal(t, value, actual[0].DataKey)
   229  	})
   230  
   231  	t.Run("with label and embed", func(t *testing.T) {
   232  		t.Parallel()
   233  
   234  		actual := make([]TestDataType2, 0)
   235  		value := randomString("v-", 20)
   236  
   237  		data := fmt.Sprintf(`
   238  		{
   239  			"internal": [{
   240  				"data_key": "%s",
   241  				"second_data_field": "%[1]s"
   242  			}]
   243  		}
   244  		`, value)
   245  
   246  		err := IntoSlicePtr(readerFromString(data), &actual, "internal")
   247  		require.NoError(t, err)
   248  		require.Len(t, actual, 1)
   249  		require.Equal(t, value, actual[0].DataKey)
   250  		require.Equal(t, value, actual[0].SecondDataField)
   251  	})
   252  
   253  	t.Run("not pointer", func(t *testing.T) {
   254  		t.Parallel()
   255  
   256  		actual := make([]TestDataType, 0)
   257  		value := randomString("v-", 20)
   258  
   259  		data := fmt.Sprintf(`
   260  		[{
   261  			"data_key": "%s"
   262  		}]
   263  		`, value)
   264  
   265  		err := IntoSlicePtr(readerFromString(data), actual, "")
   266  		require.EqualError(t, err, "expected pointer, got slice")
   267  	})
   268  
   269  	t.Run("not slice", func(t *testing.T) {
   270  		t.Parallel()
   271  
   272  		actual := new(TestDataType)
   273  		value := randomString("v-", 20)
   274  
   275  		data := fmt.Sprintf(`
   276  		{
   277  			"data_key": "%s"
   278  		}
   279  		`, value)
   280  
   281  		err := IntoSlicePtr(readerFromString(data), actual, "")
   282  		require.EqualError(t, err, "expected pointer to slice, got: *extract.TestDataType")
   283  	})
   284  }