github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/store/prolly/tree/json_diff_test.go (about)

     1  // Copyright 2023 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package tree
    16  
    17  import (
    18  	"io"
    19  	"testing"
    20  
    21  	"github.com/dolthub/go-mysql-server/sql/types"
    22  	"github.com/stretchr/testify/assert"
    23  	"github.com/stretchr/testify/require"
    24  )
    25  
    26  type jsonDiffTest struct {
    27  	name          string
    28  	from, to      types.JsonObject
    29  	expectedDiffs []JsonDiff
    30  }
    31  
    32  var simpleJsonDiffTests = []jsonDiffTest{
    33  	{
    34  		name:          "empty object, no modifications",
    35  		from:          types.JsonObject{},
    36  		to:            types.JsonObject{},
    37  		expectedDiffs: nil,
    38  	},
    39  	{
    40  		name: "insert into empty object",
    41  		from: types.JsonObject{},
    42  		to:   types.JsonObject{"a": 1},
    43  		expectedDiffs: []JsonDiff{
    44  			{
    45  				Key:  "$.\"a\"",
    46  				From: nil,
    47  				To:   &types.JSONDocument{Val: 1},
    48  				Type: AddedDiff,
    49  			},
    50  		},
    51  	},
    52  	{
    53  		name: "delete from object",
    54  		from: types.JsonObject{"a": 1},
    55  		to:   types.JsonObject{},
    56  		expectedDiffs: []JsonDiff{
    57  			{
    58  				Key:  "$.\"a\"",
    59  				From: &types.JSONDocument{Val: 1},
    60  				To:   nil,
    61  				Type: RemovedDiff,
    62  			},
    63  		},
    64  	},
    65  	{
    66  		name: "modify object",
    67  		from: types.JsonObject{"a": 1},
    68  		to:   types.JsonObject{"a": 2},
    69  		expectedDiffs: []JsonDiff{
    70  			{
    71  				Key:  "$.\"a\"",
    72  				From: &types.JSONDocument{Val: 1},
    73  				To:   &types.JSONDocument{Val: 2},
    74  				Type: ModifiedDiff,
    75  			},
    76  		},
    77  	},
    78  	{
    79  		name: "nested insert",
    80  		from: types.JsonObject{"a": types.JsonObject{}},
    81  		to:   types.JsonObject{"a": types.JsonObject{"b": 1}},
    82  		expectedDiffs: []JsonDiff{
    83  			{
    84  				Key:  "$.\"a\".\"b\"",
    85  				To:   &types.JSONDocument{Val: 1},
    86  				Type: AddedDiff,
    87  			},
    88  		},
    89  	},
    90  	{
    91  		name: "nested delete",
    92  		from: types.JsonObject{"a": types.JsonObject{"b": 1}},
    93  		to:   types.JsonObject{"a": types.JsonObject{}},
    94  		expectedDiffs: []JsonDiff{
    95  			{
    96  				Key:  "$.\"a\".\"b\"",
    97  				From: &types.JSONDocument{Val: 1},
    98  				Type: RemovedDiff,
    99  			},
   100  		},
   101  	},
   102  	{
   103  		name: "nested modify",
   104  		from: types.JsonObject{"a": types.JsonObject{"b": 1}},
   105  		to:   types.JsonObject{"a": types.JsonObject{"b": 2}},
   106  		expectedDiffs: []JsonDiff{
   107  			{
   108  				Key:  "$.\"a\".\"b\"",
   109  				From: &types.JSONDocument{Val: 1},
   110  				To:   &types.JSONDocument{Val: 2},
   111  				Type: ModifiedDiff,
   112  			},
   113  		},
   114  	},
   115  	{
   116  		name: "insert object",
   117  		from: types.JsonObject{"a": types.JsonObject{}},
   118  		to:   types.JsonObject{"a": types.JsonObject{"b": types.JsonObject{"c": 3}}},
   119  		expectedDiffs: []JsonDiff{
   120  			{
   121  				Key:  "$.\"a\".\"b\"",
   122  				To:   &types.JSONDocument{Val: types.JsonObject{"c": 3}},
   123  				Type: AddedDiff,
   124  			},
   125  		},
   126  	},
   127  	{
   128  		name: "modify to object",
   129  		from: types.JsonObject{"a": types.JsonObject{"b": 2}},
   130  		to:   types.JsonObject{"a": types.JsonObject{"b": types.JsonObject{"c": 3}}},
   131  		expectedDiffs: []JsonDiff{
   132  			{
   133  				Key:  "$.\"a\".\"b\"",
   134  				From: &types.JSONDocument{Val: 2},
   135  				To:   &types.JSONDocument{Val: types.JsonObject{"c": 3}},
   136  				Type: ModifiedDiff,
   137  			},
   138  		},
   139  	},
   140  	{
   141  		name: "modify from object",
   142  		from: types.JsonObject{"a": types.JsonObject{"b": 2}},
   143  		to:   types.JsonObject{"a": 1},
   144  		expectedDiffs: []JsonDiff{
   145  			{
   146  				Key:  "$.\"a\"",
   147  				From: &types.JSONDocument{Val: types.JsonObject{"b": 2}},
   148  				To:   &types.JSONDocument{Val: 1},
   149  				Type: ModifiedDiff,
   150  			},
   151  		},
   152  	},
   153  	{
   154  		name: "remove object",
   155  		from: types.JsonObject{"a": types.JsonObject{"b": types.JsonObject{"c": 3}}},
   156  		to:   types.JsonObject{"a": types.JsonObject{}},
   157  		expectedDiffs: []JsonDiff{
   158  			{
   159  				Key:  "$.\"a\".\"b\"",
   160  				From: &types.JSONDocument{Val: types.JsonObject{"c": 3}},
   161  				Type: RemovedDiff,
   162  			},
   163  		},
   164  	},
   165  	{
   166  		name: "insert escaped double quotes",
   167  		from: types.JsonObject{"\"a\"": "1"},
   168  		to:   types.JsonObject{"b": "\"2\""},
   169  		expectedDiffs: []JsonDiff{
   170  			{
   171  				Key:  "$.\"\\\"a\\\"\"",
   172  				From: &types.JSONDocument{Val: "1"},
   173  				To:   nil,
   174  				Type: RemovedDiff,
   175  			},
   176  			{
   177  				Key:  "$.\"b\"",
   178  				From: nil,
   179  				To:   &types.JSONDocument{Val: "\"2\""},
   180  				Type: AddedDiff,
   181  			},
   182  		},
   183  	},
   184  	{
   185  		name: "modifications returned in lexographic order",
   186  		from: types.JsonObject{"a": types.JsonObject{"1": "i"}, "aa": 2, "b": 6},
   187  		to:   types.JsonObject{"": 1, "a": types.JsonObject{}, "aa": 3, "bb": 5},
   188  		expectedDiffs: []JsonDiff{
   189  			{
   190  				Key:  "$.\"\"",
   191  				To:   &types.JSONDocument{Val: 1},
   192  				Type: AddedDiff,
   193  			},
   194  			{
   195  				Key:  "$.\"a\".\"1\"",
   196  				From: &types.JSONDocument{Val: "i"},
   197  				Type: RemovedDiff,
   198  			},
   199  			{
   200  				Key:  "$.\"aa\"",
   201  				From: &types.JSONDocument{Val: 2},
   202  				To:   &types.JSONDocument{Val: 3},
   203  				Type: ModifiedDiff,
   204  			},
   205  			{
   206  				Key:  "$.\"b\"",
   207  				From: &types.JSONDocument{Val: 6},
   208  				Type: RemovedDiff,
   209  			},
   210  			{
   211  				Key:  "$.\"bb\"",
   212  				To:   &types.JSONDocument{Val: 5},
   213  				Type: AddedDiff,
   214  			},
   215  		},
   216  	},
   217  }
   218  
   219  func TestJsonDiff(t *testing.T) {
   220  	t.Run("simple tests", func(t *testing.T) {
   221  		runTestBatch(t, simpleJsonDiffTests)
   222  	})
   223  }
   224  
   225  func runTestBatch(t *testing.T, tests []jsonDiffTest) {
   226  	for _, test := range tests {
   227  		t.Run(test.name, func(t *testing.T) {
   228  			runTest(t, test)
   229  		})
   230  	}
   231  }
   232  
   233  func runTest(t *testing.T, test jsonDiffTest) {
   234  	differ := NewJsonDiffer("$", test.from, test.to)
   235  	var actualDiffs []JsonDiff
   236  	for {
   237  		diff, err := differ.Next()
   238  		if err == io.EOF {
   239  			break
   240  		}
   241  		assert.NoError(t, err)
   242  		actualDiffs = append(actualDiffs, diff)
   243  	}
   244  
   245  	require.Equal(t, test.expectedDiffs, actualDiffs)
   246  }