github.com/sentienttechnologies/studio-go-runner@v0.0.0-20201118202441-6d21f2ced8ee/cmd/runner/json_test.go (about)

     1  // Copyright 2018-2020 (c) Cognizant Digital Business, Evolutionary AI. All rights reserved. Issued under the Apache 2.0 License.
     2  
     3  package main
     4  
     5  import (
     6  	"testing"
     7  
     8  	"github.com/go-stack/stack"
     9  	"github.com/jjeffery/kv" // MIT License
    10  
    11  	"github.com/leaf-ai/studio-go-runner/internal/runner"
    12  
    13  	jsonpatch "github.com/evanphx/json-patch"
    14  	"github.com/go-test/deep"
    15  )
    16  
    17  type ExprJSON struct {
    18  	Experiment map[string]interface{} `json:"experiment"`
    19  }
    20  
    21  // TestAJSONMergePatch is used to exercise the IETF Merge patch document for
    22  // https://tools.ietf.org/html/rfc7386
    23  //
    24  func TestAJSONMergePatch(t *testing.T) {
    25  
    26  	x1 := ExprJSON{
    27  		Experiment: map[string]interface{}{
    28  			"D": "d",
    29  			"C": "c",
    30  			"B": "b",
    31  			"A": "a",
    32  		},
    33  	}
    34  	x2 := ExprJSON{
    35  		Experiment: map[string]interface{}{
    36  			"A": 1,
    37  			"E": 2,
    38  		},
    39  	}
    40  
    41  	expected1 := `{ "experiment": { "A": "a", "B": "b", "C": "c", "D": "d", "E": 2 } }`
    42  	doc1, err := runner.ExtractMergeDoc(x1, x2)
    43  	if err != nil {
    44  		t.Fatal(err)
    45  	}
    46  	if diff := deep.Equal(expected1, doc1); diff != nil {
    47  		t.Fatal(kv.NewError("JSON Merge Patch RFC 7386 Test failed").With("diff", diff, "stack", stack.Trace().TrimRuntime()))
    48  	}
    49  
    50  	expected2 := `{ "experiment": { "A": 1, "B": "b", "C": "c", "D": "d", "E": 2 } }`
    51  	doc2, err := runner.ExtractMergeDoc(x2, x1)
    52  	if err != nil {
    53  		t.Fatal(err)
    54  	}
    55  	if diff := deep.Equal(expected2, doc2); diff != nil {
    56  		t.Fatal(kv.NewError("JSON Merge Patch RFC 7386 Test failed").With("diff", diff, "stack", stack.Trace().TrimRuntime()))
    57  	}
    58  }
    59  
    60  // TestAJSONPatch exercises a simple test case for the https://tools.ietf.org/html/rfc6902
    61  //
    62  func TestAJSONPatch(t *testing.T) {
    63  
    64  	original := []byte(`{"experiment": {"name": "John", "age": 24, "height": 3.21}}`)
    65  	patchJSON := []byte(`[
    66  		        {"op": "replace", "path": "/experiment/name", "value": "Jane"},
    67  				{"op": "remove", "path": "/experiment/height"}
    68  					]`)
    69  
    70  	patch, errGo := jsonpatch.DecodePatch(patchJSON)
    71  	if errGo != nil {
    72  		t.Fatal(kv.Wrap(errGo).With("stack", stack.Trace().TrimRuntime()))
    73  	}
    74  
    75  	modified, errGo := patch.Apply(original)
    76  	if errGo != nil {
    77  		t.Fatal(kv.Wrap(errGo).With("stack", stack.Trace().TrimRuntime()))
    78  	}
    79  
    80  	expected := `{"experiment":{"age":24,"name":"Jane"}}`
    81  	if diff := deep.Equal(expected, string(modified)); diff != nil {
    82  		t.Fatal(kv.NewError("JSON Patch RFC 6902 Test failed").With("diff", diff, "stack", stack.Trace().TrimRuntime()))
    83  	}
    84  }
    85  
    86  // TestAJSONEditor Will put together some merge style patches and some editor style patches and run these
    87  // through the runners internal editor
    88  func TestAJSONzEditor(t *testing.T) {
    89  
    90  	type testCase struct {
    91  		directive string
    92  		expected  string
    93  	}
    94  	// A table driven test is used with progressive edits and merges
    95  	testCases := []testCase{
    96  		{
    97  			`{"experiment": {"name": "testExpr", "max_run_length": 24, "run_length": 3.21}}`,
    98  			`{"experiment": {"name": "testExpr", "max_run_length": 24, "run_length": 3.21}}`,
    99  		},
   100  		{
   101  			`[{"op": "replace", "path": "/experiment/name", "value": "testExpr1"}]`,
   102  			`{"experiment": {"name": "testExpr1", "max_run_length": 24, "run_length": 3.21}}`,
   103  		},
   104  		{
   105  			`[{"op": "remove", "path": "/experiment/max_run_length"}]`,
   106  			`{"experiment": {"name": "testExpr1", "run_length": 3.21}}`,
   107  		},
   108  		{
   109  			`[{"op": "add", "path": "/experiment/addition_1", "value": "additional data 1"}]`,
   110  			`{"experiment": {"name": "testExpr1", "run_length": 3.21, "addition_1":"additional data 1"}}`,
   111  		},
   112  		{
   113  			`{"experiment": {"addition_2": "additional data 2"}}`,
   114  			`{"experiment": {"name": "testExpr1", "run_length": 3.21, "addition_1":"additional data 1", "addition_2": "additional data 2"}}`,
   115  		},
   116  	}
   117  
   118  	doc := "{}"
   119  	// run one test at a time
   120  	for _, testCase := range testCases {
   121  		newDoc, err := runner.JSONEditor(doc, []string{testCase.directive})
   122  		if err != nil {
   123  			t.Fatal(err)
   124  		}
   125  		if !jsonpatch.Equal([]byte(newDoc), []byte(testCase.expected)) {
   126  			t.Fatal(kv.NewError("JSON Editor Test failed").With("expected", testCase.expected, "actual", newDoc, "stack", stack.Trace().TrimRuntime()))
   127  		}
   128  		doc = newDoc
   129  	}
   130  
   131  	// re-run tests in incremental batches
   132  	for limit := 1; limit != len(testCases)-1; limit++ {
   133  		doc = "{}"
   134  		directives := []string{}
   135  		for _, testCase := range testCases[0:limit] {
   136  			directives = append(directives, testCase.directive)
   137  		}
   138  		doc, err := runner.JSONEditor(doc, directives)
   139  		if err != nil {
   140  			t.Fatal(err)
   141  		}
   142  		if !jsonpatch.Equal([]byte(doc), []byte(testCases[limit-1].expected)) {
   143  			t.Fatal(kv.NewError("JSON Editor Test failed").With("expected", testCases[limit-1].expected, "actual", doc, "stack", stack.Trace().TrimRuntime()))
   144  		}
   145  	}
   146  }