From 2f241a14f550598486494494998cf81f0c16b43b Mon Sep 17 00:00:00 2001 From: nabil salah Date: Thu, 15 Aug 2024 14:38:56 +0300 Subject: [PATCH] feat: bencoder encoder implementation and testing and documenting Signed-off-by: nabil salah --- pkg/bencoder.go | 38 ++++++++--------- pkg/bencoder_test.go | 97 ++++++++++++++++++++++---------------------- 2 files changed, 67 insertions(+), 68 deletions(-) diff --git a/pkg/bencoder.go b/pkg/bencoder.go index 1bd6cf4..af95a9b 100644 --- a/pkg/bencoder.go +++ b/pkg/bencoder.go @@ -11,11 +11,11 @@ func readInteger(idx *int, str *string, terminator string) (int64, error) { out := "" lim := strings.Index((*str)[*idx:], terminator) if lim == -1 { - return -1, fmt.Errorf("%s","error of terminator wasn't found") + return -1, fmt.Errorf("%s", "error of terminator wasn't found") } lim = lim + (*idx) out = (*str)[*idx:lim] - *idx = lim + *idx = lim integer, err := strconv.ParseInt(out, 10, 64) if err != nil { return -1, err @@ -25,7 +25,7 @@ func readInteger(idx *int, str *string, terminator string) (int64, error) { func readBulkString(idx *int, str *string) (interface{}, error) { out := "" - length, err := readInteger(idx, str,":") + length, err := readInteger(idx, str, ":") if err != nil { return "", err } @@ -35,17 +35,16 @@ func readBulkString(idx *int, str *string) (interface{}, error) { (*idx)++ lim := (*idx) + int(length) if lim > len(*str) { - return "", fmt.Errorf("%s","error of string lenght isn't enough") + return "", fmt.Errorf("%s", "error of string lenght isn't enough") } out = (*str)[*idx:lim] if out == "-1" { return "", nil } - *idx = lim -1 + *idx = lim - 1 return out, nil } - func readMap(idx *int, str *string) (map[interface{}]interface{}, error) { var out = make(map[interface{}]interface{}) var prev interface{} @@ -53,7 +52,7 @@ func readMap(idx *int, str *string) (map[interface{}]interface{}, error) { var val interface{} if (*str)[*idx] == 'i' { (*idx)++ - integer, err := readInteger(idx, str,"e") + integer, err := readInteger(idx, str, "e") if err != nil { return nil, err } @@ -62,7 +61,7 @@ func readMap(idx *int, str *string) (map[interface{}]interface{}, error) { if i%2 == 1 { out[prev] = val } - + prev = val continue } @@ -76,7 +75,7 @@ func readMap(idx *int, str *string) (map[interface{}]interface{}, error) { if i%2 == 1 { out[prev] = val } - + prev = val continue } @@ -91,11 +90,11 @@ func readMap(idx *int, str *string) (map[interface{}]interface{}, error) { if i%2 == 1 { out[prev] = val } - + prev = val continue } - + if (*str)[*idx] == 'd' { (*idx)++ respMap, err := readMap(idx, str) @@ -107,7 +106,7 @@ func readMap(idx *int, str *string) (map[interface{}]interface{}, error) { if i%2 == 1 { out[prev] = val } - + prev = val continue } @@ -128,7 +127,7 @@ func Decoder(str string, start ...*int) (interface{}, error) { for ; idx < len(str); idx++ { if str[idx] == 'i' { idx++ - integer, err := readInteger(&idx, &str,"e") + integer, err := readInteger(&idx, &str, "e") if err != nil { return nil, err } @@ -152,7 +151,7 @@ func Decoder(str string, start ...*int) (interface{}, error) { out = append(out, array) continue } - + if str[idx] == 'd' { idx++ respMap, err := readMap(&idx, &str) @@ -175,16 +174,17 @@ func Decoder(str string, start ...*int) (interface{}, error) { return out, nil } -func Encoder(benco interface{} ) ([]byte, error) { +// Encoder reads an interface, returning an byte array of the bencoded interface +func Encoder(benco interface{}) ([]byte, error) { var encoded []byte - + switch ty := benco.(type) { case int, int64: encoded = append(encoded, 'i') encoded = append(encoded, []byte(strconv.FormatInt(reflect.ValueOf(ty).Int(), 10))...) encoded = append(encoded, 'e') - + case string: encoded = append(encoded, []byte(strconv.Itoa(len(ty)))...) encoded = append(encoded, ':') @@ -216,10 +216,10 @@ func Encoder(benco interface{} ) ([]byte, error) { encoded = append(encoded, encodedValue...) } encoded = append(encoded, 'e') - + default: return nil, fmt.Errorf("unsupported data type") } return encoded, nil -} \ No newline at end of file +} diff --git a/pkg/bencoder_test.go b/pkg/bencoder_test.go index 3508038..9e05659 100644 --- a/pkg/bencoder_test.go +++ b/pkg/bencoder_test.go @@ -6,76 +6,75 @@ import ( "github.com/stretchr/testify/assert" ) - func TestDecoder(t *testing.T) { tests := []struct { - name string - input string - expected interface{} + name string + input string + expected interface{} expectedError bool }{ { - name: "Simple string", - input: "4:spam", - expected: "spam", + name: "Simple string", + input: "4:spam", + expected: "spam", expectedError: false, }, { - name: "Integer", - input: "i123e", - expected: int64(123), + name: "Integer", + input: "i123e", + expected: int64(123), expectedError: false, }, { - name: "List of strings", - input: "l4:spam4:foooe", - expected: []interface{}{"spam", "fooo"}, + name: "List of strings", + input: "l4:spam4:foooe", + expected: []interface{}{"spam", "fooo"}, expectedError: false, }, { - name: "Dictionary with strings", - input: "d3:bar3:moo4:spam4:foooe", - expected: map[interface {}]interface {}( - map[interface {}]interface {}{ - "bar":"moo", "spam":"fooo", + name: "Dictionary with strings", + input: "d3:bar3:moo4:spam4:foooe", + expected: map[interface{}]interface{}( + map[interface{}]interface{}{ + "bar": "moo", "spam": "fooo", }, ), expectedError: false, }, { - name: "Invalid bencoded string", - input: "invalid", - expected: nil, + name: "Invalid bencoded string", + input: "invalid", + expected: nil, expectedError: true, }, { - name: "Dictionary with strings and integers", - input: "d3:bar3:moo4:spami123ee", - expected: map[interface {}]interface {}( - map[interface {}]interface {}{ - "bar":"moo", "spam":int64(123), + name: "Dictionary with strings and integers", + input: "d3:bar3:moo4:spami123ee", + expected: map[interface{}]interface{}( + map[interface{}]interface{}{ + "bar": "moo", "spam": int64(123), }, ), expectedError: false, }, { - name: "Dictionary with strings and arrays", - input: "d3:bar3:moo4:spaml4:spam4:foooee", - expected: map[interface {}]interface {}( - map[interface {}]interface {}{ - "bar":"moo", - "spam":[]interface {}{"spam", "fooo"}, + name: "Dictionary with strings and arrays", + input: "d3:bar3:moo4:spaml4:spam4:foooee", + expected: map[interface{}]interface{}( + map[interface{}]interface{}{ + "bar": "moo", + "spam": []interface{}{"spam", "fooo"}, }, ), expectedError: false, }, { - name: "Dictionary with strings and dictionaries", - input: "d3:bar3:moo4:spamd3:bar3:moo4:spam4:foooee", - expected: map[interface {}]interface {}( - map[interface {}]interface {}{ - "bar":"moo", - "spam":map[interface {}]interface {}{"bar":"moo", "spam":"fooo"}, + name: "Dictionary with strings and dictionaries", + input: "d3:bar3:moo4:spamd3:bar3:moo4:spam4:foooee", + expected: map[interface{}]interface{}( + map[interface{}]interface{}{ + "bar": "moo", + "spam": map[interface{}]interface{}{"bar": "moo", "spam": "fooo"}, }, ), expectedError: false, @@ -101,21 +100,21 @@ func TestEncoder(t *testing.T) { expectedError bool }{ { - name: "Simple string", - input: "spam", - expected: "4:spam", + name: "Simple string", + input: "spam", + expected: "4:spam", expectedError: false, }, { - name: "Integer", - input: int64(123), - expected: "i123e", + name: "Integer", + input: int64(123), + expected: "i123e", expectedError: false, }, { - name: "List of strings", - input: []interface{}{"spam", "fooo"}, - expected: "l4:spam4:foooe", + name: "List of strings", + input: []interface{}{"spam", "fooo"}, + expected: "l4:spam4:foooe", expectedError: false, }, { @@ -143,7 +142,7 @@ func TestEncoder(t *testing.T) { { name: "Dictionary with strings and arrays", input: map[interface{}]interface{}{ - "bar": "moo", + "bar": "moo", "spam": []interface{}{"spam", "fooo"}, }, expected: "d3:bar3:moo4:spaml4:spam4:foooee", @@ -173,4 +172,4 @@ func TestEncoder(t *testing.T) { } }) } -} \ No newline at end of file +}