-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
216 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
// Package toml contains common utilities for implementing toml types. | ||
package toml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package toml | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"github.com/BurntSushi/toml" | ||
"reflect" | ||
"strings" | ||
) | ||
|
||
// Encodable is an interface for a toml with an encode method. | ||
type Encodable interface { | ||
Encode() (string, error) | ||
} | ||
|
||
// Indent is the indent we use. | ||
const Indent = " " | ||
|
||
// Encode is a helper method to allow you to encode a toml to text. | ||
// config should be passed here by pointer | ||
// TODO: use a toml parser that can poparse comments. | ||
func Encode(config interface{}) (string, error) { | ||
var buf bytes.Buffer | ||
encoder := toml.NewEncoder(&buf) | ||
encoder.Indent = Indent | ||
err := encoder.Encode(config) | ||
if err != nil { | ||
return "", fmt.Errorf("could not encode file: %w", err) | ||
} | ||
|
||
// currently, there's a bug in the parser that requires maps to be on the same level as the parent. | ||
// TODO: fix | ||
splitFile := strings.Split(buf.String(), "\n") | ||
var newLines []string | ||
for _, line := range splitFile { | ||
// get rid of double spacing on maps | ||
indentLen := len(Indent) * 2 | ||
newLines = append(newLines, strings.ReplaceAll(line, getStringOfLength(indentLen), getStringOfLength(indentLen-2))) | ||
} | ||
|
||
return strings.Join(newLines, "\n"), nil | ||
} | ||
|
||
// getStringOfLength generates a blank string of length. | ||
func getStringOfLength(length int) (res string) { | ||
for i := 0; i < length; i++ { | ||
res += " " | ||
} | ||
return res | ||
} | ||
|
||
// MarshalTextPtr should be a pointer here | ||
// Deprecated: this can be done through the library. | ||
func MarshalTextPtr(config interface{}) (text []byte, err error) { | ||
var fieldValDeref reflect.Value | ||
|
||
// make sure we have a pointer, if we don't return an error | ||
rv := eindirect(reflect.ValueOf(config)) | ||
if rv.Kind() == reflect.Ptr { | ||
// if the pointer is nil, return nothing | ||
if rv.IsNil() { | ||
return text, nil | ||
} | ||
// otherwise dereference it for decoding | ||
rv.Set(reflect.New(rv.Type().Elem())) | ||
fieldValDeref = rv.Elem() | ||
} else { | ||
return text, fmt.Errorf("this method can only be run on pointers (have %s). If your method is not a pointer, you don't need a custom text marshaller", rv.Kind().String()) | ||
} | ||
|
||
var buf bytes.Buffer | ||
encoder := toml.NewEncoder(&buf) | ||
err = encoder.Encode(fieldValDeref.Interface()) | ||
if err != nil { | ||
return text, fmt.Errorf("could not encode file: %w", err) | ||
} | ||
return buf.Bytes(), nil | ||
} | ||
|
||
// eindirect wraps a pointer. | ||
func eindirect(v reflect.Value) reflect.Value { | ||
// nolint: exhaustive | ||
switch v.Kind() { | ||
case reflect.Ptr, reflect.Interface: | ||
return eindirect(v.Elem()) | ||
default: | ||
return v | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package toml_test | ||
|
||
import ( | ||
"encoding" | ||
"fmt" | ||
"github.com/brianvoe/gofakeit/v6" | ||
. "github.com/stretchr/testify/assert" | ||
"github.com/synapsecns/sanguine/core/toml" | ||
) | ||
|
||
// WorkingConfig is a config that will work. | ||
type WorkingConfig struct { | ||
SubConfig *WorkingSubConfig `toml:"SubConfig"` | ||
} | ||
|
||
// Encode enodes the sub config. | ||
func (w *WorkingConfig) Encode() (string, error) { | ||
//nolint: wrapcheck | ||
return toml.Encode(w) | ||
} | ||
|
||
var _ toml.Encodable = &WorkingConfig{} | ||
|
||
// WorkingSubConfig is a config with that uses the marshaller method and will work | ||
// this will work because we wrap it in the working subconfig burntToml. | ||
type WorkingSubConfig struct { | ||
// OperatorKeyFile is a path to the operator key this node will use | ||
IsaConfig bool `toml:"IsAConfig"` | ||
// Name is the password used to decrypt the keyfile | ||
Name string `toml:"OperatorKeyPassword"` | ||
} | ||
|
||
// MarshallText uses the marshall text method from marshaller | ||
// Important: w must be a pointer. | ||
func (w *WorkingSubConfig) MarshalText() (text []byte, err error) { | ||
//nolint: wrapcheck | ||
return toml.MarshalTextPtr(w) | ||
} | ||
|
||
var _ encoding.TextMarshaler = &WorkingSubConfig{} | ||
|
||
// BrokenConfig is a config that will not work b/c of a missing MarshallTextPtr encode on a pointer config. | ||
type BrokenConfig struct { | ||
SubConfig *BrokenSubConfig `toml:"SubConfig"` | ||
} | ||
|
||
// Encode encodes the broken config. | ||
func (b *BrokenConfig) Encode() (string, error) { | ||
//nolint: wrapcheck | ||
return toml.Encode(b) | ||
} | ||
|
||
var _ toml.Encodable = &BrokenConfig{} | ||
|
||
// BrokenConfig is a broken config since it is passed by pointer but does not implement marshall text | ||
// this will return nothing. | ||
type BrokenSubConfig struct { | ||
// OperatorKeyFile is a path to the operator key this node will use | ||
IsaConfig bool `burntToml:"IsAConfig"` | ||
// Name is the password used to decrypt the keyfile | ||
Name string `burntToml:"OperatorKeyPassword"` | ||
} | ||
|
||
// generateWorkingConfig is a helper method to generate a working config with random data. | ||
func generateWorkingConfig() *WorkingConfig { | ||
return &WorkingConfig{ | ||
SubConfig: &WorkingSubConfig{ | ||
IsaConfig: gofakeit.Bool(), | ||
Name: gofakeit.Name(), | ||
}} | ||
} | ||
|
||
// generateBrokenCofnig generates a broken config is a helper method to generate a broken config with random data. | ||
func generateBrokenConfig() *BrokenConfig { | ||
return &BrokenConfig{SubConfig: &BrokenSubConfig{ | ||
IsaConfig: gofakeit.Bool(), | ||
Name: gofakeit.Name(), | ||
}} | ||
} | ||
|
||
// ExampleTestMarshallerImplementation shows how to use the marshaller function | ||
// this is useful for when you have a config and a sub config that uses a pointer. | ||
func ExampleMarshalTextPtr() { | ||
// if we use a struct that doesn't use marshaller text, we see no output | ||
brokenConfig := generateBrokenConfig() | ||
fmt.Println(brokenConfig.Encode()) | ||
|
||
// otherwise, we see output | ||
workingConfig := generateWorkingConfig() | ||
fmt.Println(workingConfig.Encode()) | ||
} | ||
|
||
func (t TomlSuite) TestExample() { | ||
NotPanics(t.T(), func() { | ||
ExampleMarshalTextPtr() | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package toml_test | ||
|
||
import ( | ||
"github.com/stretchr/testify/suite" | ||
"github.com/synapsecns/sanguine/core/testsuite" | ||
"testing" | ||
) | ||
|
||
// TomlSuite defines the basic test suite. | ||
type TomlSuite struct { | ||
*testsuite.TestSuite | ||
} | ||
|
||
// NewTestSuite creates a new test suite and performs some basic checks afterward. | ||
// Every test suite in the synapse library should inherit from this suite and override where necessary. | ||
func NewTestSuite(tb testing.TB) *TomlSuite { | ||
tb.Helper() | ||
return &TomlSuite{ | ||
testsuite.NewTestSuite(tb), | ||
} | ||
} | ||
|
||
func TestTomlSuite(t *testing.T) { | ||
suite.Run(t, NewTestSuite(t)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters