Skip to content

Commit

Permalink
Merge pull request #19 from 200sc/release/v0.2.4
Browse files Browse the repository at this point in the history
Release/v0.2.4
  • Loading branch information
200sc authored Dec 4, 2021
2 parents 9467711 + 4f4cba3 commit 7461765
Show file tree
Hide file tree
Showing 14 changed files with 389 additions and 18 deletions.
2 changes: 1 addition & 1 deletion bebop.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
package bebop

// Version is the library version. Should be used by CLI tools when passed a '--version' flag.
const Version = "v0.2.3"
const Version = "v0.2.4"

// A File is a structured representation of a .bop file.
type File struct {
Expand Down
98 changes: 98 additions & 0 deletions compatibility_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package bebop

import (
"bytes"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
)

Expand Down Expand Up @@ -64,3 +66,99 @@ func TestUpstreamCompatiblityFailures(t *testing.T) {
})
}
}

func TestIncompatibilityExpectations_200sc(t *testing.T) {
files, err := os.ReadDir(filepath.Join(".", "testdata", "incompatible"))
if err != nil {
t.Fatalf("failed to list incompatible files: %v", err)
}

failures := map[string]struct{}{
"import_loop_a.bop": {},
"import_loop_b.bop": {},
"import_loop_c.bop": {},
"invalid_enum_primitive.bop": {},
"invalid_import_no_const.bop": {},
"invalid_message_primitive.bop": {},
"invalid_struct_primitive.bop": {},
"recursive_struct.bop": {},
}

for _, f := range files {
if f.IsDir() {
continue
}
filename := f.Name()
if !strings.HasSuffix(filename, ".bop") {
continue
}
t.Run(filename, func(t *testing.T) {
f, err := os.Open(filepath.Join("testdata", "incompatible", filename))
if err != nil {
t.Fatalf("failed to open test file %s: %v", filename, err)
}
defer f.Close()
bopf, _, err := ReadFile(f)
if err != nil {
t.Fatalf("failed to read file %s: %v", filename, err)
}
err = bopf.Generate(bytes.NewBuffer([]byte{}), GenerateSettings{
PackageName: "generated",
})
_, shouldFail := failures[filename]
if shouldFail && err == nil {
t.Fatal("expected generation failure")
}
if !shouldFail && err != nil {
t.Fatalf("expected generation success: %v", err)
}
})
}
}

func TestIncompatibilityExpectations_Rainway(t *testing.T) {
if testing.Short() {
t.Skip("upstream tests skipped by --short")
}
skipIfUpstreamMissing(t)

files, err := os.ReadDir(filepath.Join(".", "testdata", "incompatible"))
if err != nil {
t.Fatalf("failed to list incompatible files: %v", err)
}

failures := map[string]struct{}{
"import_loop_a.bop": {},
"import_loop_b.bop": {},
"import_loop_c.bop": {},
"import_separate_a.bop": {},
"invalid_import_no_const.bop": {},
"quoted_string.bop": {},
"union.bop": {},
}

for _, f := range files {
if f.IsDir() {
continue
}
filename := f.Name()
if !strings.HasSuffix(filename, ".bop") {
continue
}
t.Run(filename, func(t *testing.T) {
cmd := exec.Command(upsteamCompilerName, "--ts", "./out.ts", "--files", filepath.Join(".", "testdata", "incompatible", filename))
out, err := cmd.CombinedOutput()
bytes.TrimSuffix(out, []byte("\n"))

_, shouldFail := failures[filename]
if shouldFail && err == nil {
t.Fatal("expected generation failure")
}
if !shouldFail && err != nil {
t.Fatalf("expected generation success: %v", err)
}

fmt.Printf("filename: %v err: %v out:%v\n", filename, err, string(out))
})
}
}
10 changes: 8 additions & 2 deletions gen_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,10 @@ func TestGenerateToFile_SeperateImports(t *testing.T) {
}
// use a separate directory to ensure duplicate definitions in combined mode
// do not cause compilation failures
os.MkdirAll(filepath.Join("testdata", "incompatible", filepath.Dir(filedef.outfile)), 0777)
err = os.MkdirAll(filepath.Join("testdata", "incompatible", filepath.Dir(filedef.outfile)), 0777)
if err != nil {
t.Fatalf("failed to mkdir: %v", err)
}
outFile := filepath.Join("testdata", "incompatible", filedef.outfile)
out, err := os.Create(outFile)
if err != nil {
Expand Down Expand Up @@ -345,7 +348,10 @@ func TestGenerateToFile_Imports(t *testing.T) {
}
// use a separate directory to ensure duplicate definitions in combined mode
// do not cause compilation failures
os.MkdirAll(filepath.Join("testdata", "generated", filename), 0777)
err = os.MkdirAll(filepath.Join("testdata", "generated", filename), 0777)
if err != nil {
t.Fatalf("failed to mkdir: %v", err)
}
outFile := filepath.Join("testdata", "generated", filename, filename+".go")
out, err := os.Create(outFile)
if err != nil {
Expand Down
7 changes: 5 additions & 2 deletions main/bebopfmt/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,13 @@ func formatFile(path string) error {
if err != nil {
return fmt.Errorf("Failed to open path to rewrite: %w", err)
}
f.Write(out.Bytes())
_, err = f.Write(out.Bytes())
if err != nil {
return fmt.Errorf("Failed to write to output: %w", err)
}
f.Close()
} else {
fmt.Println(string(out.Bytes()))
fmt.Println(out.String())
}
return nil
}
26 changes: 20 additions & 6 deletions parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,11 @@ func expectAnyOfNext(tr *tokenReader, kinds ...tokenKind) error {
return tr.Err()
}
if !next {
return readError(tr.nextToken, "expected (%v), got no token", kinds)
kindsStrs := make([]string, len(kinds))
for i, k := range kinds {
kindsStrs[i] = k.String()
}
return readError(tr.nextToken, "expected (%v), got no token", kindsStr(kinds))
}
tk := tr.Token()
found := false
Expand Down Expand Up @@ -420,11 +424,19 @@ func readMessage(tr *tokenReader) (Message, error) {
nextDeprecatedMessage := ""
nextIsDeprecated := false
for tr.Token().kind != tokenKindCloseCurly {
if !tr.Next() {
return msg, readError(tr.nextToken, "message definition ended early")
if err := expectAnyOfNext(tr,
tokenKindNewline,
tokenKindIntegerLiteral,
tokenKindOpenSquare,
tokenKindBlockComment,
tokenKindLineComment,
tokenKindCloseCurly); err != nil {
return msg, err
}
tk := tr.Token()
switch tk.kind {
case tokenKindCloseCurly:
// break
case tokenKindNewline:
nextCommentLines = []string{}
case tokenKindIntegerLiteral:
Expand Down Expand Up @@ -553,9 +565,11 @@ func readUnion(tr *tokenReader) (Union, error) {
nextCommentLines = []string{}
nextCommentTags = []Tag{}

skipEndOfLineComments(tr)
tr.Next()
// This is a close curly-- we must advance past it or the union
// will read it and believe it is complete
tr.Next()
skipEndOfLineComments(tr)
optNewline(tr)

case tokenKindOpenSquare:
if nextIsDeprecated {
Expand Down Expand Up @@ -739,7 +753,7 @@ func parseCommentTag(s string) (Tag, bool) {
// Not OK
// [tag(db:unquotedstring)]
// [tag()]

if !strings.HasPrefix(s, "[tag(") || !strings.HasSuffix(s, ")]") {
return Tag{}, false
}
Expand Down
67 changes: 66 additions & 1 deletion parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,70 @@ func TestReadFile(t *testing.T) {
expected File
}
tcs := []testCase{
{
file: "union_2",
expected: File{
Unions: []Union{
{
Name: "U2",
Fields: map[uint8]UnionField{
1: {
Struct: &Struct{
Name: "U3",
Fields: []Field{
{
Name: "hello",
FieldType: FieldType{
Simple: "uint32",
},
},
},
},
},
2: {
Message: &Message{
Name: "U4",
Fields: map[uint8]Field{
1: {
Name: "goodbye",
FieldType: FieldType{
Simple: "uint32",
},
},
},
},
},
3: {
Message: &Message{
Name: "U5",
Fields: map[uint8]Field{
1: {
Name: "goodbye",
FieldType: FieldType{
Simple: "uint32",
},
},
},
},
},
4: {
Struct: &Struct{
Name: "U6",
Fields: []Field{
{
Name: "hello",
FieldType: FieldType{
Simple: "uint32",
},
},
},
},
},
},
},
},
},
},
{
file: "tags",
expected: File{
Expand Down Expand Up @@ -1437,7 +1501,7 @@ func TestReadFileError(t *testing.T) {
{file: "invalid_message_double_deprecated", errMessage: "[2:5] expected field following deprecated annotation"},
{file: "invalid_message_hex_int", errMessage: "[1:7] strconv.ParseUint: parsing \"0x1\": invalid syntax"},
{file: "invalid_message_no_arrow", errMessage: "[1:11] expected (Arrow) got Ident"},
{file: "invalid_message_no_close", errMessage: "[1:19] message definition ended early"},
{file: "invalid_message_no_close", errMessage: "[1:19] expected (Newline, Integer Literal, Open Square, Block Comment, Line Comment, Close Curly), got no token"},
{file: "invalid_message_no_curly", errMessage: "[1:0] expected (Open Curly) got Newline"},
{file: "invalid_message_no_field_name", errMessage: "[1:15] expected (Ident) got Semicolon"},
{file: "invalid_message_no_name", errMessage: "[0:9] expected (Ident) got Open Curly"},
Expand Down Expand Up @@ -1481,6 +1545,7 @@ func TestReadFileError(t *testing.T) {
{file: "invalid_array_bad_key", errMessage: "[1:15] expected (Ident, Array, Map) got Close Square"},
{file: "invalid_array_no_close_square", errMessage: "[1:19] expected (Close Square) got Ident"},
{file: "invalid_array_suffix__no_close_square", errMessage: "[1:13] expected (Close Square) got Ident"},
{file: "invalid_union_no_message_int", errMessage: "[5:14] expected (Newline, Integer Literal, Open Square, Block Comment, Line Comment, Close Curly) got Ident"},
}
for _, tc := range tcs {
tc := tc
Expand Down
14 changes: 14 additions & 0 deletions testdata/base/union_2.bop
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
union U2 {
1 -> struct U3{
uint32 hello;
}
2 -> message U4{
1 -> uint32 goodbye;
}
3 -> message U5{
1 -> uint32 goodbye;
}
4 -> struct U6{
uint32 hello;
}
}
2 changes: 1 addition & 1 deletion testdata/formatted/quoted_string_formatted.bop
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// we support escaped quotes inside of deprecated stings. rainway does not as of 2.2.6
// we support escaped quotes inside of deprecated stings. rainway does not as of 2.3.1
struct QuotedString {
[deprecated("\"deprecated\"")]
int32 X;
Expand Down
4 changes: 3 additions & 1 deletion testdata/incompatible/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

Files in this directory should reasonably be supported by rainway bebop but are not, and we support, or vice versa.

## causes
## Sample causes

"uint8" is a supported type, but "int8" is not.

Rainway allows overwriting primitive types with message, struct, or enum definitions. We do not.

We do not allow recursive struct definitions, as they will never terminate when encoded or parsed. Rainway does not have a check for this.

See `compatibility_test.go` for which files specifically fail for which compilers.
Loading

0 comments on commit 7461765

Please sign in to comment.