diff --git a/.github/workflows/goreleaser.yaml b/.github/workflows/goreleaser.yaml index b1bc89f..7457589 100644 --- a/.github/workflows/goreleaser.yaml +++ b/.github/workflows/goreleaser.yaml @@ -15,7 +15,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.14 + go-version: 1.16 - name: Run GoReleaser uses: goreleaser/goreleaser-action@v2 diff --git a/base64/loader.go b/base64/loader.go index 8e4e1e9..ab1ad47 100644 --- a/base64/loader.go +++ b/base64/loader.go @@ -2,13 +2,14 @@ package base64 import ( "encoding/base64" + lua "github.com/yuin/gopher-lua" ) -// Preload adds yaml to the given Lua state's package.preload table. After it +// Preload adds base64 to the given Lua state's package.preload table. After it // has been preloaded, it can be loaded using require: // -// local yaml = require("yaml") +// local base64 = require("base64") func Preload(L *lua.LState) { L.PreloadModule("base64", Loader) } diff --git a/hex/README.md b/hex/README.md new file mode 100644 index 0000000..cdfa2d5 --- /dev/null +++ b/hex/README.md @@ -0,0 +1,43 @@ +# hex [![GoDoc](https://godoc.org/github.com/vadv/gopher-lua-libs/hex?status.svg)](https://godoc.org/github.com/vadv/gopher-lua-libs/hex) + +Lua module for [encoding/hex](https://pkg.go.dev/encoding/hex) + +## Usage + +### Encoding + +```lua +local hex = require("hex") + +s = hex.RawStdEncoding:encode_to_string("foo\01bar") +print(s) +Zm9vAWJhcg + +s = hex.StdEncoding:encode_to_string("foo\01bar") +print(s) +Zm9vAWJhcg== + +s = hex.RawURLEncoding:encode_to_string("this is a and should be encoded") +print(s) +dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA + +s = hex.URLEncoding:encode_to_string("this is a and should be encoded") +print(s) +dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA== + +``` + +### Decoding + +```lua +local hex = require 'hex' + +decoded, err = hex.decode_string("666f6f62617262617a") +assert(not err, err) +print(decoded) +foobar + +encoded = hex.encode_to_string(decoded) +print(encoded) +666f6f62617262617a +``` diff --git a/hex/api.go b/hex/api.go new file mode 100644 index 0000000..52b54c7 --- /dev/null +++ b/hex/api.go @@ -0,0 +1,84 @@ +// Package hex implements hex encode/decode functionality for lua. +package hex + +import ( + "encoding/hex" + "io" + + lio "github.com/vadv/gopher-lua-libs/io" + lua "github.com/yuin/gopher-lua" +) + +const ( + hexEncoderType = "hex.Encoder" + hexDecoderType = "hex.Decoder" +) + +// LVHexEncoder creates a new Lua user data for the hex encoder +func LVHexEncoder(L *lua.LState, writer io.Writer) lua.LValue { + ud := L.NewUserData() + ud.Value = writer + L.SetMetatable(ud, L.GetTypeMetatable(hexEncoderType)) + return ud +} + +// LVHexDecoder creates a new Lua user data for the hex decoder +func LVHexDecoder(L *lua.LState, reader io.Reader) lua.LValue { + ud := L.NewUserData() + ud.Value = reader + L.SetMetatable(ud, L.GetTypeMetatable(hexDecoderType)) + return ud +} + +// DecodeString decodes the encoded string with the encoding +func DecodeString(L *lua.LState) int { + encoded := L.CheckString(1) + L.Pop(L.GetTop()) + decoded, err := hex.DecodeString(encoded) + if err != nil { + L.Push(lua.LNil) + L.Push(lua.LString(err.Error())) + return 2 + } + L.Push(lua.LString(decoded)) + return 1 +} + +// EncodeToString decodes the string with the encoding +func EncodeToString(L *lua.LState) int { + decoded := L.CheckString(1) + L.Pop(L.GetTop()) + encoded := hex.EncodeToString([]byte(decoded)) + L.Push(lua.LString(encoded)) + return 1 +} + +// registerHexEncoder Registers the encoder type and its methods +func registerHexEncoder(L *lua.LState) { + mt := L.NewTypeMetatable(hexEncoderType) + L.SetGlobal(hexEncoderType, mt) + L.SetField(mt, "__index", lio.WriterFuncTable(L)) +} + +// registerHexDecoder Registers the decoder type and its methods +func registerHexDecoder(L *lua.LState) { + mt := L.NewTypeMetatable(hexDecoderType) + L.SetGlobal(hexDecoderType, mt) + L.SetField(mt, "__index", lio.ReaderFuncTable(L)) +} + +func NewEncoder(L *lua.LState) int { + writer := lio.CheckIOWriter(L, 1) + L.Pop(L.GetTop()) + encoder := hex.NewEncoder(writer) + L.Push(LVHexEncoder(L, encoder)) + return 1 +} + +func NewDecoder(L *lua.LState) int { + reader := lio.CheckIOReader(L, 1) + L.Pop(L.GetTop()) + decoder := hex.NewDecoder(reader) + L.Push(LVHexDecoder(L, decoder)) + return 1 +} diff --git a/hex/api_test.go b/hex/api_test.go new file mode 100644 index 0000000..0535547 --- /dev/null +++ b/hex/api_test.go @@ -0,0 +1,14 @@ +package hex + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/vadv/gopher-lua-libs/strings" + "github.com/vadv/gopher-lua-libs/tests" +) + +func TestApi(t *testing.T) { + preload := tests.SeveralPreloadFuncs(Preload, strings.Preload) + assert.NotZero(t, tests.RunLuaTestFile(t, preload, "./test/test_api.lua")) +} diff --git a/hex/example_test.go b/hex/example_test.go new file mode 100644 index 0000000..247b567 --- /dev/null +++ b/hex/example_test.go @@ -0,0 +1,81 @@ +package hex + +import ( + "log" + + "github.com/vadv/gopher-lua-libs/strings" + lua "github.com/yuin/gopher-lua" +) + +func ExampleEncodeToString() { + state := lua.NewState() + defer state.Close() + Preload(state) + source := ` + local hex = require 'hex' + s = hex.encode_to_string("foo\01bar") + print(s) +` + if err := state.DoString(source); err != nil { + log.Fatal(err.Error()) + } + // Output: + // 666f6f01626172 +} + +func ExampleDecodeString() { + state := lua.NewState() + defer state.Close() + Preload(state) + source := ` + local hex = require 'hex' + s, err = hex.decode_string("666f6f01626172") + assert(not err, err) + print(s) +` + if err := state.DoString(source); err != nil { + log.Fatal(err.Error()) + } + // Output: + // foobar +} + +func ExampleNewEncoder() { + state := lua.NewState() + defer state.Close() + Preload(state) + strings.Preload(state) + source := ` + local hex = require 'hex' + local strings = require 'strings' + local writer = strings.new_builder() + encoder = hex.new_encoder(writer) + encoder:write("foo\01bar") + print(writer:string()) +` + if err := state.DoString(source); err != nil { + log.Fatal(err.Error()) + } + // Output: + // 666f6f01626172 +} + +func ExampleNewDecoder() { + state := lua.NewState() + defer state.Close() + Preload(state) + strings.Preload(state) + source := ` + local hex = require 'hex' + local strings = require 'strings' + local reader = strings.new_reader('666f6f01626172') + decoder = hex.new_decoder(reader) + local s = decoder:read("*a") + print(s) +` + if err := state.DoString(source); err != nil { + log.Fatal(err.Error()) + } + // Output: + // foobar +} diff --git a/hex/loader.go b/hex/loader.go new file mode 100644 index 0000000..ec63f44 --- /dev/null +++ b/hex/loader.go @@ -0,0 +1,28 @@ +package hex + +import lua "github.com/yuin/gopher-lua" + +// Preload adds hex to the given Lua state's package.preload table. After it +// has been preloaded, it can be loaded using require: +// +// local hex = require("hex") +func Preload(L *lua.LState) { + L.PreloadModule("hex", Loader) +} + +// Loader is the module loader function. +func Loader(L *lua.LState) int { + registerHexDecoder(L) + registerHexEncoder(L) + + // Register the encodings offered by hex go module. + t := L.NewTable() + L.SetFuncs(t, map[string]lua.LGFunction{ + "decode_string": DecodeString, + "encode_to_string": EncodeToString, + "new_encoder": NewEncoder, + "new_decoder": NewDecoder, + }) + L.Push(t) + return 1 +} diff --git a/hex/test/test_api.lua b/hex/test/test_api.lua new file mode 100644 index 0000000..4732430 --- /dev/null +++ b/hex/test/test_api.lua @@ -0,0 +1,43 @@ +local hex = require 'hex' +local strings = require 'strings' +local assert = require 'assert' + +function TestHexCodec(t) + local tests = { + { + encoded = "48656c6c6f20776f726c64", -- "Hello world" in hex + decoded = "Hello world", + }, + { + encoded = "", + decoded = "", + }, + } + for _, tt in ipairs(tests) do + t:Run("hex.decode_string(" .. tostring(tt.encoded) .. ")", function(t) + local got = hex.decode_string(tt.encoded) + assert:Equal(t, tt.decoded, got) + end) + + t:Run("hex.encode_to_string(" .. tostring(tt.decoded) .. ")", function(t) + local got = hex.encode_to_string(tt.decoded) + assert:Equal(t, tt.encoded, got) + end) + end +end + +function TestEncoder(t) + local writer = strings.new_builder() + local encoder = hex.new_encoder(writer) + encoder:write("foo", "bar", "baz") + encoder:close() + local s = writer:string() + assert:Equal(t, "666f6f62617262617a", s) +end + +function TestDecoder(t) + local reader = strings.new_reader("666f6f62617262617a") + local decoder = hex.new_decoder(reader) + local s = decoder:read("*a") + assert:Equal(t, "foobarbaz", s) +end diff --git a/plugin/preload.go b/plugin/preload.go index 8b30441..acc5112 100644 --- a/plugin/preload.go +++ b/plugin/preload.go @@ -12,6 +12,7 @@ import ( "github.com/vadv/gopher-lua-libs/db" "github.com/vadv/gopher-lua-libs/filepath" "github.com/vadv/gopher-lua-libs/goos" + "github.com/vadv/gopher-lua-libs/hex" "github.com/vadv/gopher-lua-libs/http" "github.com/vadv/gopher-lua-libs/humanize" "github.com/vadv/gopher-lua-libs/inspect" @@ -44,6 +45,7 @@ func PreloadAll(L *lua.LState) { argparse.Preload(L) base64.Preload(L) + bit.Preload(L) cert_util.Preload(L) chef.Preload(L) cloudwatch.Preload(L) @@ -52,6 +54,7 @@ func PreloadAll(L *lua.LState) { db.Preload(L) filepath.Preload(L) goos.Preload(L) + hex.Preload(L) http.Preload(L) humanize.Preload(L) inspect.Preload(L) @@ -75,5 +78,4 @@ func PreloadAll(L *lua.LState) { xmlpath.Preload(L) yaml.Preload(L) zabbix.Preload(L) - bit.Preload(L) } diff --git a/tests/assertions.lua b/tests/assertions.lua index 8b168be..792f451 100644 --- a/tests/assertions.lua +++ b/tests/assertions.lua @@ -152,7 +152,7 @@ function assertions:NoErrorf(t, err, fmt, ...) if not err then return true end - return self:Fail(t, string.format([[ + return self:Failf(t, string.format([[ Error: Received unexpected error: %s