From d96900ba17528d8e3553d48608a47bfd1710091e Mon Sep 17 00:00:00 2001
From: Mark Puha
Date: Thu, 5 Jun 2025 20:16:00 +0200
Subject: [PATCH] feat: parser error cases & generator skeleton
---
device/internal/junk-tag/generator.go | 14 ++++
device/internal/junk-tag/parser.go | 87 +++++++++++++++++++++++++
device/internal/junk-tag/parser_test.go | 60 +++++++++++++++++
go.mod | 4 ++
go.sum | 10 +++
5 files changed, 175 insertions(+)
create mode 100644 device/internal/junk-tag/generator.go
create mode 100644 device/internal/junk-tag/parser.go
create mode 100644 device/internal/junk-tag/parser_test.go
diff --git a/device/internal/junk-tag/generator.go b/device/internal/junk-tag/generator.go
new file mode 100644
index 0000000..ca96dee
--- /dev/null
+++ b/device/internal/junk-tag/generator.go
@@ -0,0 +1,14 @@
+package junktag
+
+type Generator interface {
+ Generate() []byte
+}
+
+type newGenerator func(string) (Generator, error)
+
+type BytesGenerator struct {
+}
+
+func (b *BytesGenerator) Generate() []byte {
+ return nil
+}
diff --git a/device/internal/junk-tag/parser.go b/device/internal/junk-tag/parser.go
new file mode 100644
index 0000000..0160a4e
--- /dev/null
+++ b/device/internal/junk-tag/parser.go
@@ -0,0 +1,87 @@
+package junktag
+
+import (
+ "fmt"
+ "regexp"
+ "strings"
+)
+
+type Enum string
+
+const (
+ EnumBytes Enum = "b"
+ EnumCounter Enum = "c"
+ EnumTimestamp Enum = "t"
+ EnumRandomBytes Enum = "r"
+ EnumWaitTimeout Enum = "wt"
+ EnumWaitResponse Enum = "wr"
+)
+
+var validEnum = map[Enum]newGenerator{
+ EnumBytes: func(s string) (Generator, error) { return &BytesGenerator{}, nil },
+ EnumCounter: func(s string) (Generator, error) { return &BytesGenerator{}, nil },
+ EnumTimestamp: func(s string) (Generator, error) { return &BytesGenerator{}, nil },
+ EnumRandomBytes: func(s string) (Generator, error) { return &BytesGenerator{}, nil },
+ EnumWaitTimeout: func(s string) (Generator, error) { return &BytesGenerator{}, nil },
+ EnumWaitResponse: func(s string) (Generator, error) { return &BytesGenerator{}, nil },
+}
+
+type Foo struct {
+ x []Generator
+}
+
+type Tag struct {
+ Name Enum
+ Param string
+}
+
+func parseTags(input string) ([]Tag, error) {
+ // Regular expression to match
+ re := regexp.MustCompile(`([a-zA-Z]+)(?:\s+([^>]+))?>`)
+
+ matches := re.FindAllStringSubmatch(input, -1)
+ tags := make([]Tag, 0, len(matches))
+
+ for _, match := range matches {
+ tag := Tag{
+ Name: Enum(match[1]),
+ }
+ if len(match) > 2 && match[2] != "" {
+ tag.Param = strings.TrimSpace(match[2])
+ }
+ tags = append(tags, tag)
+ }
+
+ return tags, nil
+}
+
+func Parse(input string) (Foo, error) {
+ inputSlice := strings.Split(input, "<")
+ fmt.Printf("%v\n", inputSlice)
+ if len(inputSlice) <= 1 {
+ return Foo{}, fmt.Errorf("empty input: %s", input)
+ }
+
+ for _, inputParam := range inputSlice[1:] {
+ if len(inputParam) == 1 {
+ return Foo{}, fmt.Errorf("empty tag in input: %s", inputSlice)
+ } else if strings.Count(inputParam, ">") != 1 {
+ return Foo{}, fmt.Errorf("ill formated input: %s", input)
+ }
+
+ tags, _ := parseTags(inputParam)
+ for _, tag := range tags {
+ fmt.Printf("Tag: %s, Param: %s\n", tag.Name, tag.Param)
+ gen, ok := validEnum[tag.Name]
+ if !ok {
+ return Foo{}, fmt.Errorf("invalid tag")
+ }
+ _, err := gen(tag.Param)
+ if err != nil {
+ return Foo{}, fmt.Errorf("")
+ }
+ }
+ }
+
+ return Foo{}, nil
+}
diff --git a/device/internal/junk-tag/parser_test.go b/device/internal/junk-tag/parser_test.go
new file mode 100644
index 0000000..6c1f33b
--- /dev/null
+++ b/device/internal/junk-tag/parser_test.go
@@ -0,0 +1,60 @@
+package junktag
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestParse(t *testing.T) {
+ type args struct {
+ input string
+ }
+ tests := []struct {
+ name string
+ args args
+ wantErr error
+ }{
+ {
+ name: "empty",
+ args: args{input: ""},
+ wantErr: fmt.Errorf("ill formated input"),
+ },
+ {
+ name: "extra >",
+ args: args{input: ">"},
+ wantErr: fmt.Errorf("ill formated input"),
+ },
+ {
+ name: "extra <",
+ args: args{input: "<"},
+ wantErr: fmt.Errorf("ill formated input"),
+ },
+ {
+ name: "empty <>",
+ args: args{input: "<>"},
+ wantErr: fmt.Errorf("empty tag in input"),
+ },
+ {
+ name: "invalid tag",
+ args: args{input: ""},
+ wantErr: fmt.Errorf("invalid tag"),
+ },
+ {
+ name: "valid",
+ args: args{input: ""},
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ _, err := Parse(tt.args.input)
+
+ // TODO: ErrorAs doesn't work as you think
+ // if tt.wantErr != nil {
+ require.ErrorAs(t, err, &tt.wantErr)
+ // return
+ // }
+ })
+ }
+}
diff --git a/go.mod b/go.mod
index 608969f..c150a4b 100644
--- a/go.mod
+++ b/go.mod
@@ -3,6 +3,7 @@ module github.com/amnezia-vpn/amneziawg-go
go 1.24
require (
+ github.com/stretchr/testify v1.10.0
github.com/tevino/abool/v2 v2.1.0
golang.org/x/crypto v0.36.0
golang.org/x/net v0.37.0
@@ -12,6 +13,9 @@ require (
)
require (
+ github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/btree v1.1.3 // indirect
+ github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/time v0.9.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/go.sum b/go.sum
index 497f949..ec3fa7f 100644
--- a/go.sum
+++ b/go.sum
@@ -1,7 +1,13 @@
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tevino/abool/v2 v2.1.0 h1:7w+Vf9f/5gmKT4m4qkayb33/92M+Um45F2BkHOR+L/c=
github.com/tevino/abool/v2 v2.1.0/go.mod h1:+Lmlqk6bHDWHqN1cbxqhwEAwMPXgc8I1SDEamtseuXY=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
@@ -16,5 +22,9 @@ golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gvisor.dev/gvisor v0.0.0-20250130013005-04f9204697c6 h1:6B7MdW3OEbJqOMr7cEYU9bkzvCjUBX/JlXk12xcANuQ=
gvisor.dev/gvisor v0.0.0-20250130013005-04f9204697c6/go.mod h1:5DMfjtclAbTIjbXqO1qCe2K5GKKxWz2JHvCChuTcJEM=