github.com/unigraph-dev/dgraph@v1.1.1-0.20200923154953-8b52b426f765/chunker/chunk_test.go (about)

     1  /*
     2   * Copyright 2017-2018 Dgraph Labs, Inc. and Contributors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package chunker
    18  
    19  import (
    20  	"bufio"
    21  	"bytes"
    22  	"fmt"
    23  	"io"
    24  	"strings"
    25  	"testing"
    26  
    27  	"github.com/stretchr/testify/require"
    28  )
    29  
    30  func bufioReader(str string) *bufio.Reader {
    31  	return bufio.NewReader(strings.NewReader(str))
    32  }
    33  
    34  // Test that problems at the start of the JSON document are caught.
    35  func TestJSONLoadStart(t *testing.T) {
    36  	var tests = []struct {
    37  		json string
    38  		desc string
    39  	}{
    40  		{"[,]", "Illegal rune found \",\", expecting {"},
    41  		{"[a]", "Illegal rune found \"a\", expecting {"},
    42  		{"{}]", "JSON map is followed by an extraneous ]"},
    43  		{"These are words.", "file is not JSON"},
    44  		{"\x1f\x8b\x08\x08\x3e\xc7\x0a\x5c\x00\x03\x65\x6d\x70\x74\x79\x00", "file is binary"},
    45  	}
    46  
    47  	for _, test := range tests {
    48  		chunker := NewChunker(JsonFormat, 1000)
    49  		_, err := chunker.Chunk(bufioReader(test.json))
    50  		require.True(t, err != nil && err != io.EOF, test.desc)
    51  	}
    52  }
    53  
    54  func TestChunkJSONMapAndArray(t *testing.T) {
    55  	tests := []struct {
    56  		json   string
    57  		chunks []string
    58  	}{
    59  		{`[]`, []string{"[]"}},
    60  		{`[{}]`, []string{"[{}]"}},
    61  		{`[{"user": "alice"}]`, []string{`[{"user":"alice"}]`}},
    62  		{`[{"user": "alice", "age": 26}]`, []string{`[{"user":"alice","age":26}]`}},
    63  		{`[{"user": "alice", "age": 26}, {"name": "bob"}]`, []string{`[{"user":"alice","age":26},{"name":"bob"}]`}},
    64  	}
    65  
    66  	for _, test := range tests {
    67  		chunker := NewChunker(JsonFormat, 1000)
    68  		r := bufioReader(test.json)
    69  		var chunks []string
    70  		for {
    71  			chunkBuf, err := chunker.Chunk(r)
    72  			if err != nil {
    73  				require.Equal(t, io.EOF, err, "Received error for %s", test)
    74  			}
    75  
    76  			chunks = append(chunks, chunkBuf.String())
    77  
    78  			if err == io.EOF {
    79  				break
    80  			}
    81  		}
    82  
    83  		require.Equal(t, test.chunks, chunks, "Got different chunks")
    84  	}
    85  }
    86  
    87  // Test that problems at the start of the next chunk are caught.
    88  func TestJSONLoadReadNext(t *testing.T) {
    89  	var tests = []struct {
    90  		json string
    91  		desc string
    92  	}{
    93  		{"[,]", "no start of JSON map 1"},
    94  		{"[ this is not really a json array ]", "no start of JSON map 2"},
    95  		{"[{]", "malformed map"},
    96  		{"[{}", "malformed array"},
    97  	}
    98  	for _, test := range tests {
    99  		chunker := NewChunker(JsonFormat, 1000)
   100  		reader := bufioReader(test.json)
   101  		chunkBuf, err := chunker.Chunk(reader)
   102  		if err == nil {
   103  			err = chunker.Parse(chunkBuf)
   104  			require.True(t, err != nil && err != io.EOF, test.desc)
   105  		} else {
   106  			require.True(t, err != io.EOF, test.desc)
   107  		}
   108  	}
   109  }
   110  
   111  // Test that loading first chunk succeeds. No need to test that loaded chunk is valid.
   112  func TestJSONLoadSuccessFirst(t *testing.T) {
   113  	var tests = []struct {
   114  		json string
   115  		expt string
   116  		desc string
   117  	}{
   118  		{"[{}]", "[{}]", "empty map"},
   119  		{`[{"closingDelimeter":"}"}]`, `[{"closingDelimeter":"}"}]`, "quoted closing brace"},
   120  		{`[{"company":"dgraph"}]`, `[{"company":"dgraph"}]`, "simple, compact map"},
   121  		{
   122  			"[\n  {\n    \"company\" : \"dgraph\"\n  }\n]\n",
   123  			"[{\"company\":\"dgraph\"}]",
   124  			"simple, pretty map",
   125  		},
   126  		{
   127  			`[{"professor":"Alastor \"Mad-Eye\" Moody"}]`,
   128  			`[{"professor":"Alastor \"Mad-Eye\" Moody"}]`,
   129  			"escaped balanced quotes",
   130  		},
   131  		{
   132  
   133  			`[{"something{": "}something"}]`,
   134  			`[{"something{":"}something"}]`,
   135  			"escape quoted brackets",
   136  		},
   137  		{
   138  			`[{"height":"6'0\""}]`,
   139  			`[{"height":"6'0\""}]`,
   140  			"escaped unbalanced quote",
   141  		},
   142  		{
   143  			`[{"house":{"Hermione":"Gryffindor","Cedric":"Hufflepuff","Luna":"Ravenclaw","Draco":"Slytherin",}}]`,
   144  			`[{"house":{"Hermione":"Gryffindor","Cedric":"Hufflepuff","Luna":"Ravenclaw","Draco":"Slytherin",}}]`,
   145  			"nested braces",
   146  		},
   147  	}
   148  	for _, test := range tests {
   149  		chunker := NewChunker(JsonFormat, 1000)
   150  		reader := bufioReader(test.json)
   151  		json, err := chunker.Chunk(reader)
   152  		if err == io.EOF {
   153  			// pass
   154  		} else {
   155  			require.NoError(t, err, test.desc)
   156  		}
   157  		//fmt.Fprintf(os.Stderr, "err = %v, json = %v\n", err, json)
   158  		require.Equal(t, test.expt, json.String(), test.desc)
   159  	}
   160  }
   161  
   162  // Test that loading all chunks succeeds. No need to test that loaded chunk is valid.
   163  func TestJSONLoadSuccessAll(t *testing.T) {
   164  	var testDoc = `
   165  [
   166  	{},
   167  	{
   168  		"closingDelimeter" : "}"
   169  	},
   170  	{
   171  		"company" : "dgraph",
   172  		"age": 3
   173  	},
   174  	{
   175  		"professor" : "Alastor \"Mad-Eye\" Moody",
   176  		"height"    : "6'0\""
   177  	},
   178  	{
   179  		"house" : {
   180  			"Hermione" : "Gryffindor",
   181  			"Cedric"   : "Hufflepuff",
   182  			"Luna"     : "Ravenclaw",
   183  			"Draco"    : "Slytherin"
   184  		}
   185  	}
   186  ]`
   187  	var testChunks = []string{
   188  		`{}`,
   189  		`{
   190  		"closingDelimeter" : "}"
   191  	}`,
   192  		`{
   193  		"company" : "dgraph",
   194  		"age": 3
   195  	}`,
   196  		`{
   197  		"professor" : "Alastor \"Mad-Eye\" Moody",
   198  		"height"    : "6'0\""
   199  	}`,
   200  		`{
   201  		"house" : {
   202  			"Hermione" : "Gryffindor",
   203  			"Cedric"   : "Hufflepuff",
   204  			"Luna"     : "Ravenclaw",
   205  			"Draco"    : "Slytherin"
   206  		}
   207  	}`,
   208  	}
   209  
   210  	chunker := NewChunker(JsonFormat, 1000)
   211  	reader := bufioReader(testDoc)
   212  
   213  	var json *bytes.Buffer
   214  	var idx int
   215  
   216  	var err error
   217  	for idx = 0; err == nil; idx++ {
   218  		desc := fmt.Sprintf("reading chunk #%d", idx+1)
   219  		json, err = chunker.Chunk(reader)
   220  		//fmt.Fprintf(os.Stderr, "err = %v, json = %v\n", err, json)
   221  		if err != io.EOF {
   222  			require.NoError(t, err, desc)
   223  			require.Equal(t, testChunks[idx], json.String(), desc)
   224  		}
   225  	}
   226  	require.Equal(t, io.EOF, err, "end reading JSON document")
   227  }