1
0
mirror of https://github.com/getsops/sops.git synced 2026-02-05 12:45:21 +01:00
Files
sops/stores/json/store_test.go

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

638 lines
13 KiB
Go
Raw Permalink Normal View History

2016-09-01 14:16:41 -07:00
package json
import (
"testing"
"github.com/getsops/sops/v3"
"github.com/getsops/sops/v3/config"
"github.com/stretchr/testify/assert"
2016-09-01 14:16:41 -07:00
)
func TestDecodeJSON(t *testing.T) {
in := `
{
"glossary":{
"title":"example glossary",
"GlossDiv":{
"title":"S",
"GlossList":{
"GlossEntry":{
"ID":"SGML",
"SortAs":"SGML",
"GlossTerm":"Standard Generalized Markup Language",
"Acronym":"SGML",
"Abbrev":"ISO 8879:1986",
"GlossDef":{
"para":"A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso":[
"GML",
"XML"
]
},
"GlossSee":"markup"
}
}
}
}
}
`
2016-09-01 14:16:41 -07:00
expected := sops.TreeBranch{
sops.TreeItem{
Key: "glossary",
Value: sops.TreeBranch{
sops.TreeItem{
Key: "title",
Value: "example glossary",
},
sops.TreeItem{
Key: "GlossDiv",
Value: sops.TreeBranch{
sops.TreeItem{
Key: "title",
Value: "S",
},
sops.TreeItem{
Key: "GlossList",
Value: sops.TreeBranch{
sops.TreeItem{
Key: "GlossEntry",
Value: sops.TreeBranch{
sops.TreeItem{
Key: "ID",
Value: "SGML",
},
sops.TreeItem{
Key: "SortAs",
Value: "SGML",
},
sops.TreeItem{
Key: "GlossTerm",
Value: "Standard Generalized Markup Language",
},
sops.TreeItem{
Key: "Acronym",
Value: "SGML",
},
sops.TreeItem{
Key: "Abbrev",
Value: "ISO 8879:1986",
},
sops.TreeItem{
Key: "GlossDef",
Value: sops.TreeBranch{
sops.TreeItem{
Key: "para",
Value: "A meta-markup language, used to create markup languages such as DocBook.",
},
sops.TreeItem{
Key: "GlossSeeAlso",
Value: []interface{}{
"GML",
"XML",
},
},
},
},
sops.TreeItem{
Key: "GlossSee",
Value: "markup",
},
},
},
},
},
},
},
},
},
}
branch, err := Store{}.treeBranchFromJSON([]byte(in))
assert.Nil(t, err)
assert.Equal(t, expected, branch)
}
func TestDecodeSimpleJSONObject(t *testing.T) {
in := `{"foo": "bar", "baz": 2}`
expected := sops.TreeBranch{
sops.TreeItem{
Key: "foo",
Value: "bar",
},
sops.TreeItem{
Key: "baz",
Value: 2.0,
},
}
branch, err := Store{}.treeBranchFromJSON([]byte(in))
assert.Nil(t, err)
assert.Equal(t, expected, branch)
}
Don't consider io.EOF returned by Decoder.Token as error [`Decoder.Token`](https://golang.org/pkg/encoding/json/#Decoder.Token) returns nil, io.EOF at the input stream. This caused the output json to have no "data" key for an input containing a number: ``` { "sops": { "kms": null, "gcp_kms": null, "lastmodified": "2018-01-14T14:51:51Z", "mac": "ENC[AES256_GCM,data:miI91EH0VGqTY9DuJweV61++dq1LmdBwbU/tkaznCeVo2H7z0vws0FdDJiKUiyCwd+PYkpklinVyGWzxDjgR1yWch+9uU4zFkwSiNwLTdQRitYE9Kwxd37E7+AFmJtZIfIdUZsx/gFP4YZ4Pn2cgVK6n9sNRyaGhR4PyCp7TXT4=,iv:XnyghTNLba1edrVYk8sum38pe736T3L5yGJMmBocDyE=,tag:b3z730u8+hPiNxmg8REFHg==,type:str]", "pgp": [ { "created_at": "2018-01-14T14:51:51Z", "enc": "-----BEGIN PGP MESSAGE-----\n\nwcFMA90gOM45xlRNARAAj8AtDWZakRBpMmqRH3z6F+hIkyt2xpP911MAHpU1e4ma\nNZfUcKJybg2XFbAj40uDSEE1o1+hebU18nzYVwVUiDKBGN5f3rSgAIgtcK8u9JT2\nhRPndP7wkFK1t1+n3ne40ZotdqYefCLjHUalmS8Ka5wYDXGD9fOR3zBoaJ1VFWYu\nZyOltpqK76AFZ8dJkBBXcZCKfmZ2h2C9/tfSq5Hjibzddd/zit09zXsyHE6McFJU\n3YPGmGQ/kE+/1vkELIF3suGy7yB3Um0cRCEVnHoZJkE+lRZtxKKJ91oKLOfwJkoT\nOAHmeRJxDE45eae/wbWS4KHUFJ2IvfnUuaNCVrnYyzRP05wFxAuZI7XcV3ckVfaM\nBW2GkAUESfY9zYkTm/lOpUhAjEpqzjG+lSCt9VdHMMqOl8N4z6U5qzznm1ZL4Wf9\nbEV0zRc5XECmM6yjx7KHA8ivjdgxpKY9HgBI5ZkfjgoORfOaZaiVdteRmEOQM3yS\nWN+QTt4dkcfsqdpmYyHbCatgV9rsZdcIHS1kZ4EK7HMKzwR9+caRFA+o3NOm0hyx\nbNnMldVFr771KFoneau13A5HdZGdZRO7qMfpVZjdDQ8dFR1xtAimeoSGqIv5rcT3\n8UzrnNuSkHlPZHNgBloV5DoFLtWzd9VZCOl1KyLQLsSqQgbi1mbZlAQWfdWbwqHS\n4AHk3ef1I8MjQxVJFD4jSgC80OHzIeBK4C/heu/gfuKjuYWI4MLlPiuN6e+yoFT+\nR75GX1GgqTWP52gwxstEibTQ7n9zl6/gUeQ1/T+QOFDfajpawb8+xxyx4kjOzPnh\nU4MA\n=VSfw\n-----END PGP MESSAGE-----", "fp": "C8F69F5F7059C32B3328DFE48BE9D15D0B0D06EB" } ], "unencrypted_suffix": "_unencrypted", "version": "3.0.0" } } ``` After the change: ``` { "data": "ENC[AES256_GCM,data:PVw=,iv:cCDbWu1jdYkCIUcF/BtZGBs6mSWtdTI5ZF/A/i7RxIY=,tag:sFtal0nSo2koPDxnaKxLgA==,type:str]", "sops": { "kms": null, "gcp_kms": null, "lastmodified": "2018-01-14T14:52:38Z", "mac": "ENC[AES256_GCM,data:BOyvRlaMKIGRcNOnmBGnN/Qz7i/l6Lhl5lx1OJ1VMb6nhuKkhCySktGVYOElUTgLc3CDKLfELNKiID2i6HKAkSAWQyYC1tIPAQTcBtnVd2Pt7Adzz8i8JFzWT+sc5rKLCOljnXwcXsxbmhrWwfQFj57wVWkvZTRNLfNZkcMnykw=,iv:JxCILR1qxAk391tTmLf/hXlr1L/JQWqhLbFHYR04HjI=,tag:0LSWWPWEBeK1Gm2mi4UBNA==,type:str]", "pgp": [ { "created_at": "2018-01-14T14:52:38Z", "enc": "-----BEGIN PGP MESSAGE-----\n\nwcFMA90gOM45xlRNARAAR+FmJBwY4gnpUUZSwWRrwJ+PLhBzVXoIfZ2zqhk+gkvl\nGZyi62mCM5ZVoVPf8Pw+a9cQi+IzJHgKEOT/6PIp1chw7DhnoGbFJExcE3inniou\nlLo2pFTRH5jTvCE3yIIR/l1b9VMrtnOcZuYx9SobLjIv4wKtY1gMkbmrG2IDLmMT\n9QYM/MT/aCcUA/u6bYz8+ZjAS7NUEifji/SkZkYlL1tdCEdiHU/Cl4gScOhqcIsK\nGWGa+1jnxnYOmYq3FDMb90RSPgU8xkzl9EQIInF2t4K3Zj7E+9J93Y7N2udpNGah\nebPwxS4VTCLl1p69q9+nhO8rn9ySjeTjIoJwPoNDzWVowQEmUPZCTz+A28RKi02l\nGsuYxCzD5aF8cRhZbLk882fCAo77U9TiYYa00cq8kTqnCpZmtp3BevrdWTswJwin\n/TID0DOflahzj7iUP8MAVI2nzGosmCWEFiVONWq2l2z7ND78Y65G/d5hM3zv71U/\n1z0B8zzxZSbFFTV2YjADwWdizpeXJFJuVdynCQdPxt8qfNZVXcQfIHmYwh4M3k3U\nv5yV491mwCPNAJAoBaNJoKLnXx3ae4Aic4s2sF3V+AKK6rNiWtuAWsyjuwzmTse2\ntQisNTez5m+6r5seC7YvC2i9Vb2DNzqYn4M/13tHjxpPrNxdCGNneM1FKG8a03nS\n4AHk5BBSjhL9oc/o7zf8AsoFdeE2A+BR4KnhNXbg2eJlJCnO4IvlzVv3wYVwmh5W\nfyHqIQAX3ICb43o6Vo2/AGANvM5BdA3gX+ToyYFHsSMttWLz4zAUJWe04pRx0/rh\n73EA\n=0ON2\n-----END PGP MESSAGE-----", "fp": "C8F69F5F7059C32B3328DFE48BE9D15D0B0D06EB" } ], "unencrypted_suffix": "_unencrypted", "version": "3.0.0" } } ``` Fixes #235
2018-01-14 20:41:37 +05:30
func TestDecodeNumber(t *testing.T) {
in := `42`
_, err := Store{}.treeBranchFromJSON([]byte(in))
assert.NotNil(t, err)
assert.Equal(t, "Expected JSON object start, got 42 of type float64 instead", err.Error())
}
func TestDecodeArray(t *testing.T) {
in := ` [42] `
_, err := Store{}.treeBranchFromJSON([]byte(in))
assert.NotNil(t, err)
assert.Equal(t, "Expected JSON object start, got delimiter [ instead", err.Error())
}
func TestDecodeEmpty(t *testing.T) {
in := ``
_, err := Store{}.treeBranchFromJSON([]byte(in))
assert.NotNil(t, err)
assert.Equal(t, "EOF", err.Error())
Don't consider io.EOF returned by Decoder.Token as error [`Decoder.Token`](https://golang.org/pkg/encoding/json/#Decoder.Token) returns nil, io.EOF at the input stream. This caused the output json to have no "data" key for an input containing a number: ``` { "sops": { "kms": null, "gcp_kms": null, "lastmodified": "2018-01-14T14:51:51Z", "mac": "ENC[AES256_GCM,data:miI91EH0VGqTY9DuJweV61++dq1LmdBwbU/tkaznCeVo2H7z0vws0FdDJiKUiyCwd+PYkpklinVyGWzxDjgR1yWch+9uU4zFkwSiNwLTdQRitYE9Kwxd37E7+AFmJtZIfIdUZsx/gFP4YZ4Pn2cgVK6n9sNRyaGhR4PyCp7TXT4=,iv:XnyghTNLba1edrVYk8sum38pe736T3L5yGJMmBocDyE=,tag:b3z730u8+hPiNxmg8REFHg==,type:str]", "pgp": [ { "created_at": "2018-01-14T14:51:51Z", "enc": "-----BEGIN PGP MESSAGE-----\n\nwcFMA90gOM45xlRNARAAj8AtDWZakRBpMmqRH3z6F+hIkyt2xpP911MAHpU1e4ma\nNZfUcKJybg2XFbAj40uDSEE1o1+hebU18nzYVwVUiDKBGN5f3rSgAIgtcK8u9JT2\nhRPndP7wkFK1t1+n3ne40ZotdqYefCLjHUalmS8Ka5wYDXGD9fOR3zBoaJ1VFWYu\nZyOltpqK76AFZ8dJkBBXcZCKfmZ2h2C9/tfSq5Hjibzddd/zit09zXsyHE6McFJU\n3YPGmGQ/kE+/1vkELIF3suGy7yB3Um0cRCEVnHoZJkE+lRZtxKKJ91oKLOfwJkoT\nOAHmeRJxDE45eae/wbWS4KHUFJ2IvfnUuaNCVrnYyzRP05wFxAuZI7XcV3ckVfaM\nBW2GkAUESfY9zYkTm/lOpUhAjEpqzjG+lSCt9VdHMMqOl8N4z6U5qzznm1ZL4Wf9\nbEV0zRc5XECmM6yjx7KHA8ivjdgxpKY9HgBI5ZkfjgoORfOaZaiVdteRmEOQM3yS\nWN+QTt4dkcfsqdpmYyHbCatgV9rsZdcIHS1kZ4EK7HMKzwR9+caRFA+o3NOm0hyx\nbNnMldVFr771KFoneau13A5HdZGdZRO7qMfpVZjdDQ8dFR1xtAimeoSGqIv5rcT3\n8UzrnNuSkHlPZHNgBloV5DoFLtWzd9VZCOl1KyLQLsSqQgbi1mbZlAQWfdWbwqHS\n4AHk3ef1I8MjQxVJFD4jSgC80OHzIeBK4C/heu/gfuKjuYWI4MLlPiuN6e+yoFT+\nR75GX1GgqTWP52gwxstEibTQ7n9zl6/gUeQ1/T+QOFDfajpawb8+xxyx4kjOzPnh\nU4MA\n=VSfw\n-----END PGP MESSAGE-----", "fp": "C8F69F5F7059C32B3328DFE48BE9D15D0B0D06EB" } ], "unencrypted_suffix": "_unencrypted", "version": "3.0.0" } } ``` After the change: ``` { "data": "ENC[AES256_GCM,data:PVw=,iv:cCDbWu1jdYkCIUcF/BtZGBs6mSWtdTI5ZF/A/i7RxIY=,tag:sFtal0nSo2koPDxnaKxLgA==,type:str]", "sops": { "kms": null, "gcp_kms": null, "lastmodified": "2018-01-14T14:52:38Z", "mac": "ENC[AES256_GCM,data:BOyvRlaMKIGRcNOnmBGnN/Qz7i/l6Lhl5lx1OJ1VMb6nhuKkhCySktGVYOElUTgLc3CDKLfELNKiID2i6HKAkSAWQyYC1tIPAQTcBtnVd2Pt7Adzz8i8JFzWT+sc5rKLCOljnXwcXsxbmhrWwfQFj57wVWkvZTRNLfNZkcMnykw=,iv:JxCILR1qxAk391tTmLf/hXlr1L/JQWqhLbFHYR04HjI=,tag:0LSWWPWEBeK1Gm2mi4UBNA==,type:str]", "pgp": [ { "created_at": "2018-01-14T14:52:38Z", "enc": "-----BEGIN PGP MESSAGE-----\n\nwcFMA90gOM45xlRNARAAR+FmJBwY4gnpUUZSwWRrwJ+PLhBzVXoIfZ2zqhk+gkvl\nGZyi62mCM5ZVoVPf8Pw+a9cQi+IzJHgKEOT/6PIp1chw7DhnoGbFJExcE3inniou\nlLo2pFTRH5jTvCE3yIIR/l1b9VMrtnOcZuYx9SobLjIv4wKtY1gMkbmrG2IDLmMT\n9QYM/MT/aCcUA/u6bYz8+ZjAS7NUEifji/SkZkYlL1tdCEdiHU/Cl4gScOhqcIsK\nGWGa+1jnxnYOmYq3FDMb90RSPgU8xkzl9EQIInF2t4K3Zj7E+9J93Y7N2udpNGah\nebPwxS4VTCLl1p69q9+nhO8rn9ySjeTjIoJwPoNDzWVowQEmUPZCTz+A28RKi02l\nGsuYxCzD5aF8cRhZbLk882fCAo77U9TiYYa00cq8kTqnCpZmtp3BevrdWTswJwin\n/TID0DOflahzj7iUP8MAVI2nzGosmCWEFiVONWq2l2z7ND78Y65G/d5hM3zv71U/\n1z0B8zzxZSbFFTV2YjADwWdizpeXJFJuVdynCQdPxt8qfNZVXcQfIHmYwh4M3k3U\nv5yV491mwCPNAJAoBaNJoKLnXx3ae4Aic4s2sF3V+AKK6rNiWtuAWsyjuwzmTse2\ntQisNTez5m+6r5seC7YvC2i9Vb2DNzqYn4M/13tHjxpPrNxdCGNneM1FKG8a03nS\n4AHk5BBSjhL9oc/o7zf8AsoFdeE2A+BR4KnhNXbg2eJlJCnO4IvlzVv3wYVwmh5W\nfyHqIQAX3ICb43o6Vo2/AGANvM5BdA3gX+ToyYFHsSMttWLz4zAUJWe04pRx0/rh\n73EA\n=0ON2\n-----END PGP MESSAGE-----", "fp": "C8F69F5F7059C32B3328DFE48BE9D15D0B0D06EB" } ], "unencrypted_suffix": "_unencrypted", "version": "3.0.0" } } ``` Fixes #235
2018-01-14 20:41:37 +05:30
}
2016-09-01 14:16:41 -07:00
func TestDecodeNestedJSONObject(t *testing.T) {
in := `{"foo": {"foo": "bar"}}`
expected := sops.TreeBranch{
sops.TreeItem{
Key: "foo",
Value: sops.TreeBranch{
sops.TreeItem{
Key: "foo",
Value: "bar",
},
},
},
}
branch, err := Store{}.treeBranchFromJSON([]byte(in))
assert.Nil(t, err)
assert.Equal(t, expected, branch)
}
func TestDecodeJSONWithArray(t *testing.T) {
in := `{"foo": {"foo": [1, 2, 3]}, "bar": "baz"}`
expected := sops.TreeBranch{
sops.TreeItem{
Key: "foo",
Value: sops.TreeBranch{
sops.TreeItem{
Key: "foo",
Value: []interface{}{1.0, 2.0, 3.0},
},
},
},
sops.TreeItem{
Key: "bar",
Value: "baz",
},
}
branch, err := Store{}.treeBranchFromJSON([]byte(in))
assert.Nil(t, err)
assert.Equal(t, expected, branch)
}
2016-09-08 13:21:32 -07:00
func TestDecodeJSONArrayOfObjects(t *testing.T) {
in := `{"foo": [{"bar": "foo"}, {"foo": "bar"}]}`
expected := sops.TreeBranch{
sops.TreeItem{
Key: "foo",
Value: []interface{}{
sops.TreeBranch{
sops.TreeItem{
Key: "bar",
Value: "foo",
},
},
sops.TreeBranch{
sops.TreeItem{
Key: "foo",
Value: "bar",
},
},
},
},
}
branch, err := Store{}.treeBranchFromJSON([]byte(in))
assert.Nil(t, err)
assert.Equal(t, expected, branch)
}
func TestDecodeJSONArrayOfArrays(t *testing.T) {
in := `{"foo": [[["foo", {"bar": "foo"}]]]}`
expected := sops.TreeBranch{
sops.TreeItem{
Key: "foo",
Value: []interface{}{
[]interface{}{
[]interface{}{
"foo",
sops.TreeBranch{
sops.TreeItem{
Key: "bar",
Value: "foo",
},
},
},
},
},
},
}
branch, err := Store{}.treeBranchFromJSON([]byte(in))
assert.Nil(t, err)
assert.Equal(t, expected, branch)
}
2016-09-01 14:16:41 -07:00
func TestEncodeSimpleJSON(t *testing.T) {
branch := sops.TreeBranch{
sops.TreeItem{
Key: "foo",
Value: "bar",
},
sops.TreeItem{
Key: "foo",
Value: 3.0,
},
sops.TreeItem{
Key: "bar",
Value: false,
},
}
out, err := Store{}.jsonFromTreeBranch(branch)
assert.Nil(t, err)
expected, _ := Store{}.treeBranchFromJSON(out)
assert.Equal(t, expected, branch)
}
func TestEncodeJSONWithEscaping(t *testing.T) {
branch := sops.TreeBranch{
sops.TreeItem{
Key: "foo\\bar",
Value: "value",
},
sops.TreeItem{
Key: "a_key_with\"quotes\"",
Value: 4.0,
},
sops.TreeItem{
Key: "baz\\\\foo",
Value: 2.0,
},
}
out, err := Store{}.jsonFromTreeBranch(branch)
assert.Nil(t, err)
expected, _ := Store{}.treeBranchFromJSON(out)
assert.Equal(t, expected, branch)
}
func TestEncodeJSONArrayOfObjects(t *testing.T) {
tree := sops.Tree{
Branches: sops.TreeBranches{
sops.TreeBranch{
sops.TreeItem{
Key: "foo",
Value: []interface{}{
sops.TreeBranch{
sops.TreeItem{
Key: "foo",
Value: 3,
},
sops.TreeItem{
Key: "bar",
Value: false,
},
},
2,
},
},
},
},
}
expected := `{
"foo": [
{
"foo": 3,
"bar": false
},
2
]
}
`
store := Store{
config: config.JSONStoreConfig{
Indent: -1,
},
}
out, err := store.EmitPlainFile(tree.Branches)
assert.Nil(t, err)
assert.Equal(t, expected, string(out))
}
func TestUnmarshalMetadataFromNonSOPSFile(t *testing.T) {
data := []byte(`{"hello": 2}`)
store := Store{}
_, err := store.LoadEncryptedFile(data)
assert.Equal(t, sops.MetadataNotFound, err)
}
func TestLoadJSONFormattedBinaryFile(t *testing.T) {
// This is JSON data, but we want SOPS to interpret it as binary,
// e.g. because the --input-type binary flag was provided.
data := []byte(`{"hello": 2}`)
store := BinaryStore{}
branches, err := store.LoadPlainFile(data)
assert.Nil(t, err)
assert.Equal(t, "data", branches[0][0].Key)
}
func TestEmitBinaryFile(t *testing.T) {
store := BinaryStore{}
data, err := store.EmitPlainFile(sops.TreeBranches{
sops.TreeBranch{
sops.TreeItem{
Key: "data",
Value: "foo",
},
},
})
assert.Nil(t, err)
assert.Equal(t, []byte("foo"), data)
}
func TestEmitBinaryFileWrongBranches(t *testing.T) {
store := BinaryStore{}
data, err := store.EmitPlainFile(sops.TreeBranches{
sops.TreeBranch{
sops.TreeItem{
Key: "data",
Value: "bar",
},
},
sops.TreeBranch{
sops.TreeItem{
Key: "data",
Value: "bar",
},
},
})
assert.Nil(t, data)
assert.Contains(t, err.Error(), "there must be exactly one tree branch")
data, err = store.EmitPlainFile(sops.TreeBranches{})
assert.Nil(t, data)
assert.Contains(t, err.Error(), "there must be exactly one tree branch")
}
func TestEmitBinaryFileNoData(t *testing.T) {
store := BinaryStore{}
data, err := store.EmitPlainFile(sops.TreeBranches{
sops.TreeBranch{
sops.TreeItem{
Key: "foo",
Value: "bar",
},
},
})
assert.Nil(t, data)
assert.Contains(t, err.Error(), "no binary data found in tree")
}
func TestEmitBinaryFileWrongDataType(t *testing.T) {
store := BinaryStore{}
data, err := store.EmitPlainFile(sops.TreeBranches{
sops.TreeBranch{
sops.TreeItem{
Key: "data",
Value: sops.TreeItem{
Key: "foo",
Value: "bar",
},
},
},
})
assert.Nil(t, data)
assert.Contains(t, err.Error(), "'data' key in tree does not have a string value")
}
func TestEmitValueString(t *testing.T) {
bytes, err := (&Store{}).EmitValue("hello")
assert.Nil(t, err)
assert.Equal(t, []byte("\"hello\""), bytes)
}
func TestIndentTwoSpaces(t *testing.T) {
tree := sops.Tree{
Branches: sops.TreeBranches{
sops.TreeBranch{
sops.TreeItem{
Key: "foo",
Value: []interface{}{
sops.TreeBranch{
sops.TreeItem{
Key: "foo",
Value: 3,
},
sops.TreeItem{
Key: "bar",
Value: false,
},
},
2,
},
},
},
},
}
expected := `{
"foo": [
{
"foo": 3,
"bar": false
},
2
]
}
`
store := Store{
config: config.JSONStoreConfig{
Indent: 2,
},
}
out, err := store.EmitPlainFile(tree.Branches)
assert.Nil(t, err)
assert.Equal(t, expected, string(out))
}
func TestIndentDefault(t *testing.T) {
tree := sops.Tree{
Branches: sops.TreeBranches{
sops.TreeBranch{
sops.TreeItem{
Key: "foo",
Value: []interface{}{
sops.TreeBranch{
sops.TreeItem{
Key: "foo",
Value: 3,
},
sops.TreeItem{
Key: "bar",
Value: false,
},
},
2,
},
},
},
},
}
expected := `{
"foo": [
{
"foo": 3,
"bar": false
},
2
]
}
`
store := Store{
config: config.JSONStoreConfig{
Indent: -1,
},
}
out, err := store.EmitPlainFile(tree.Branches)
assert.Nil(t, err)
assert.Equal(t, expected, string(out))
}
func TestNoIndent(t *testing.T) {
tree := sops.Tree{
Branches: sops.TreeBranches{
sops.TreeBranch{
sops.TreeItem{
Key: "foo",
Value: []interface{}{
sops.TreeBranch{
sops.TreeItem{
Key: "foo",
Value: 3,
},
sops.TreeItem{
Key: "bar",
Value: false,
},
},
2,
},
},
},
},
}
expected := `{
"foo": [
{
"foo": 3,
"bar": false
},
2
]
}
`
store := Store{
config: config.JSONStoreConfig{
Indent: 0,
},
}
out, err := store.EmitPlainFile(tree.Branches)
assert.Nil(t, err)
assert.Equal(t, expected, string(out))
}
func TestConflictingAttributes(t *testing.T) {
// See https://stackoverflow.com/a/23195243
// Duplicate keys in json is technically valid, but discouraged.
// Implementations may handle them differently. ECMA-262 says
//
// > In the case where there are duplicate name Strings within an object,
// > lexically preceding values for the same key shall be overwritten.
data := `
{
"hello": "Sops config file",
"hello": "Doubles are ok",
"hello": ["repeatedly"],
"hello": 3.14
}
`
s := new(Store)
_, err := s.LoadPlainFile([]byte(data))
assert.Nil(t, err)
}
func TestComments(t *testing.T) {
tree := sops.Tree{
Branches: sops.TreeBranches{
sops.TreeBranch{
sops.TreeItem{
Key: "foo",
Value: []interface{}{
sops.Comment{Value: " comment 0"},
sops.TreeBranch{
sops.TreeItem{
Key: sops.Comment{Value: " comment 1"},
Value: nil,
},
sops.TreeItem{
Key: "foo",
Value: 3,
},
sops.TreeItem{
Key: sops.Comment{Value: " comment 2"},
Value: nil,
},
sops.TreeItem{
Key: sops.Comment{Value: " comment 3"},
Value: nil,
},
sops.TreeItem{
Key: "bar",
Value: false,
},
sops.TreeItem{
Key: sops.Comment{Value: " comment 4"},
Value: nil,
},
sops.TreeItem{
Key: sops.Comment{Value: " comment 5"},
Value: nil,
},
},
sops.Comment{Value: " comment 6"},
sops.Comment{Value: " comment 7"},
2,
sops.Comment{Value: " comment 8"},
sops.Comment{Value: " comment 9"},
},
},
},
},
}
expected := `{
"foo": [
{
"foo": 3,
"bar": false
},
2
]
}
`
store := Store{
config: config.JSONStoreConfig{
Indent: 2,
},
}
out, err := store.EmitPlainFile(tree.Branches)
assert.Nil(t, err)
assert.Equal(t, expected, string(out))
}