Add testing

This commit is contained in:
Arkadiy Tetelman committed 2023-01-01 00:47:20 -08:00
1 parent d57358e131
commit 1d5e583df5
7 files changed
+181 -10

No files matched your search

+19
View File
@@ -0,0 +1,19 @@
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.19
- name: Install Protoc
run: |
sudo apt install -y protobuf-compiler
go install google.golang.org/protobuf/cmd/[email protected]
- name: Test
run: make test
- name: Build
run: make build
+4 -1
View File
@@ -1,5 +1,8 @@
build: build:
go build -o protodump cmd/main.go go build -o protodump cmd/protodump/main.go
fmt:
go fmt ./...
test: test:
go test -v ./... go test -v ./...
-2
View File
@@ -13,8 +13,6 @@ go build -o protodump cmd/protodump/main.go
./protodump -file <file to extract from> -output <output directory> ./protodump -file <file to extract from> -output <output directory>
``` ```
This was thrown together in a day and still has bugs :)
## Getting in touch ## Getting in touch
Feel free to contact me on twitter: https://twitter.com/arkadiyt Feel free to contact me on twitter: https://twitter.com/arkadiyt
+1 -1
View File
@@ -1,7 +1,7 @@
package main package main
import ( import (
"flag" "flag"
"fmt" "fmt"
"log" "log"
"os" "os"
+40
View File
@@ -0,0 +1,40 @@
syntax = "proto3";
package helloworld;
option go_package = "./;helloworld";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
rpc StreamMethodServer (StreamRequest) returns (stream StreamReply) {}
}
message HelloRequest {
message Test {
string blah = 1;
}
enum NestedEnum {
BLAH = 0;
}
string name = 1;
helloworld.HelloRequest.Test blah = 2;
helloworld.HelloRequest.NestedEnum blahblah = 3;
helloworld.HelloReply blaha = 4;
}
message HelloReply {
helloworld.HelloRequest.Test blah = 2;
helloworld.HelloRequest.NestedEnum blahblah = 3;
string message = 1;
}
message StreamRequest {
string message = 1;
}
message StreamReply {
string message = 1;
}
+56 -5
View File
@@ -2,6 +2,7 @@ package protodump
import ( import (
"fmt" "fmt"
"reflect"
"strconv" "strconv"
"strings" "strings"
@@ -204,6 +205,60 @@ func (pd *ProtoDefinition) writeImport(fileImport protoreflect.FileImport) {
pd.write("\";\n") pd.write("\";\n")
} }
func (pd *ProtoDefinition) writeStringFileOptions(name string, value string) {
pd.write("option ")
pd.write(name)
pd.write(" = \"")
pd.write(value)
pd.write("\";\n")
}
func (pd *ProtoDefinition) writeBoolFileOptions(name string, value bool) {
pd.writeStringFileOptions(name, strconv.FormatBool(value))
}
func (pd *ProtoDefinition) writeFileOptions() {
optionDefinitions := []struct {
OptionName string
FieldName string
}{
{"java_package", "JavaPackage"},
{"java_outer_classname", "JavaOuterClassname"},
{"java_multiple_files", "JavaMultipleFiles"},
{"java_string_check_utf8", "JavaStringCheckUtf8"},
// TODO OptimizeMode: https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto#L384
{"go_package", "GoPackage"},
// TODO generic services: https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto#L403
// TODO deprecated: https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto#L412
{"cc_enable_arenas", "CcEnableArenas"},
{"objc_class_prefix", "ObjcClassPrefix"},
{"csharp_namespace", "CsharpNamespace"},
{"swift_prefix", "SwiftPrefix"},
{"php_class_prefix", "PhpClassPrefix"},
{"php_namespace", "PhpNamespace"},
{"php_metadata_namespace", "PhpMetadataNamespace"},
{"ruby_package", "RubyPackage"},
}
options := reflect.ValueOf(pd.pb.GetOptions()).Elem()
printedOption := false
for _, option := range optionDefinitions {
elemPtr := options.FieldByName(option.FieldName)
if !elemPtr.IsNil() {
elem := elemPtr.Elem()
if elem.Kind() == reflect.String {
pd.writeStringFileOptions(option.OptionName, elem.String())
} else if elem.Kind() == reflect.Bool {
pd.writeBoolFileOptions(option.OptionName, elem.Bool())
}
printedOption = true
}
}
if printedOption {
pd.write("\n")
}
}
func (pd *ProtoDefinition) writeFileDescriptor() { func (pd *ProtoDefinition) writeFileDescriptor() {
pd.write("syntax = \"") pd.write("syntax = \"")
pd.write(pd.descriptor.Syntax().String()) pd.write(pd.descriptor.Syntax().String())
@@ -213,11 +268,7 @@ func (pd *ProtoDefinition) writeFileDescriptor() {
pd.write(string(pd.descriptor.Package().Name())) pd.write(string(pd.descriptor.Package().Name()))
pd.write(";\n\n") pd.write(";\n\n")
// TODO need to handle FileOptions pd.writeFileOptions()
filepb := protodesc.ToFileDescriptorProto(pd.descriptor)
options := filepb.Options
if options != nil {
}
for i := 0; i < pd.descriptor.Imports().Len(); i++ { for i := 0; i < pd.descriptor.Imports().Len(); i++ {
pd.writeImport(pd.descriptor.Imports().Get(i)) pd.writeImport(pd.descriptor.Imports().Get(i))
+61 -1
View File
@@ -1,18 +1,78 @@
package protodump package protodump
import ( import (
"bytes"
"encoding/hex"
"fmt"
"os" "os"
"os/exec"
"path"
"regexp"
"strings"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
const FIXTURES = "fixtures"
var regex = regexp.MustCompile("(?m)var .* = \\[\\]byte{([^}]*)}")
func convertProtoToFileDescriptor(filePath string) ([]byte, error) {
dir, err := os.MkdirTemp("", "")
if err != nil {
return nil, err
}
defer os.RemoveAll(dir)
err = exec.Command("protoc", fmt.Sprintf("--go_out=%s", dir), filePath).Run()
if err != nil {
return nil, err
}
fileName := fmt.Sprintf("%s.pb.go", strings.TrimSuffix(path.Base(filePath), ".proto"))
data, err := os.ReadFile(path.Join(dir, fileName))
if err != nil {
return nil, err
}
match := regex.FindSubmatch(data)
if len(match) != 2 {
return nil, fmt.Errorf("Could not find file descriptor bytes in %s", fileName)
}
var hexString strings.Builder
for _, char := range strings.ToLower(string(bytes.ReplaceAll(match[1], []byte("0x"), []byte{}))) {
r := rune(char)
if (r >= '0' && r <= '9') || (r >= 'a' && r <= 'f') {
hexString.WriteRune(r)
}
}
result, err := hex.DecodeString(hexString.String())
if err != nil {
return nil, err
}
return result, nil
}
func TestDefinitions(t *testing.T) { func TestDefinitions(t *testing.T) {
files, err := os.ReadDir("fixtures") files, err := os.ReadDir(FIXTURES)
assert.NoError(t, err) assert.NoError(t, err)
for _, file := range files { for _, file := range files {
t.Run(file.Name(), func(t *testing.T) { t.Run(file.Name(), func(t *testing.T) {
filePath := path.Join(FIXTURES, file.Name())
descriptor, err := convertProtoToFileDescriptor(filePath)
assert.NoError(t, err)
expected, err := os.ReadFile(filePath)
assert.NoError(t, err)
actual, err := NewFromBytes(descriptor)
assert.NoError(t, err)
assert.Equal(t, string(expected), actual.String())
}) })
} }
} }