Skip to content

Commit

Permalink
fix: update parseKey to use std lib
Browse files Browse the repository at this point in the history
Signed-off-by: Marko Kungla <[email protected]>
  • Loading branch information
mkungla committed Jan 30, 2024
1 parent 4d304d7 commit 5607003
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 159 deletions.
20 changes: 10 additions & 10 deletions pkg/vars/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# VARS

![license](https://img.shields.io/github/license/happy-sdk/vars)
[![PkgGoDev](https://pkg.go.dev/badge/github.com/happy-sdk/happy-go/vars)](https://pkg.go.dev/github.com/happy-sdk/happy-go/vars)
![tests](https://github.com/happy-sdk/happy-go/vars/workflows/tests/badge.svg)
[![Go Report Card](https://goreportcard.com/badge/github.com/happy-sdk/happy-go/vars)](https://goreportcard.com/report/github.com/happy-sdk/happy-go/vars)
[![PkgGoDev](https://pkg.go.dev/badge/github.com/happy-sdk/happy/pkg/vars)](https://pkg.go.dev/github.com/happy-sdk/happy/pkg/vars)
![tests](https://github.com/happy-sdk/happy/pkg/vars/workflows/tests/badge.svg)
[![Go Report Card](https://goreportcard.com/badge/github.com/happy-sdk/happy/pkg/vars)](https://goreportcard.com/report/github.com/happy-sdk/happy/pkg/vars)
[![Coverage Status](https://coveralls.io/repos/github/happy-sdk/vars/badge.svg?branch=main)](https://coveralls.io/github/happy-sdk/vars?branch=main)
<!-- [![benchmarks](https://github.com/mkungla/vars/workflows/benchmarks/badge.svg)](https://dashboard.github.orijtech.com/graphs?repo=https%3A%2F%2Fgithub.com%2Fmkungla%2Fvars.git) -->
![GitHub last commit](https://img.shields.io/github/last-commit/happy-sdk/vars)
![GitHub last commit](https://img.shields.io/github/last-commit/happy-sdk/happy/vars)

## About
Package vars provides the API to parse variables from various input formats/types to common key value pair vars.Value or variable sets to vars.Collection
Expand All @@ -15,19 +15,19 @@ Package vars provides the API to parse variables from various input formats/type
## Install

```
go get github.com/happy-sdk/happy-go/vars
go get github.com/happy-sdk/happy/pkg/vars
```

## Usage

**working with [vars.Value](https://pkg.go.dev/github.com/happy-sdk/happy-go/vars#Value)**
**working with [vars.Value](https://pkg.go.dev/github.com/happy-sdk/happy/pkg/vars#Value)**

```go
package main

import (
"fmt"
"github.com/happy-sdk/happy-go/vars"
"github.com/happy-sdk/happy/pkg/vars"
)

func main() {
Expand Down Expand Up @@ -89,7 +89,7 @@ func main() {
}
```

**working with [vars.Collection](https://pkg.go.dev/github.com/happy-sdk/happy-go/vars#Collection)**
**working with [vars.Collection](https://pkg.go.dev/github.com/happy-sdk/happy/pkg/vars#Collection)**

> Because of underlying `sync.Map` it is meant to be populated once and read many times
> read thoroughly sync.Map docs to understand where .Collection may not me right for you!
Expand All @@ -99,7 +99,7 @@ package main

import (
"fmt"
"github.com/happy-sdk/happy-go/vars"
"github.com/happy-sdk/happy/pkg/vars"
)

func main() {
Expand Down Expand Up @@ -149,7 +149,7 @@ package main
import (
"fmt"
"io/ioutil"
"github.com/happy-sdk/happy-go/vars"
"github.com/happy-sdk/happy/pkg/vars"
)

func main() {
Expand Down
104 changes: 36 additions & 68 deletions pkg/vars/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@

package vars

import (
"strings"
"unicode"
"unicode/utf8"
)

var (
// for faster lookup our custom Unicode Character Table rules
// we have following two tables.
Expand All @@ -23,84 +29,46 @@ var (
// table for Variable key. based on IEEE Std 1003.1-2001.
// See The Open Group specification for more details.
// https://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html
func parseKey(k string) (key string, err error) {
var (
ltrimd bool
rtrimd bool
)
ilen := len(k)
for i := 0; !ltrimd && i < ilen; i++ {
ki := k[0]
if keyAutoTrimableChars[ki] == 1 {
k = k[1:]
continue
}
func parseKey(str string) (key string, err error) {
if len(str) == 0 {
return "", ErrKeyIsEmpty
}

if ki >= 48 && ki <= 57 {
return "", ErrKeyPrefix
}
ltrimd = true
if !utf8.ValidString(str) {
return "", ErrKeyNotValidUTF8
}
for i := len(k) - 1; !rtrimd && i > 0; i-- {
if keyAutoTrimableChars[k[i]] == 1 {
k = k[0:i]
continue

// remove most outer trimmable characters
key = strings.TrimFunc(str, func(c rune) bool {
if c < 256 {
return keyAutoTrimableChars[c] == 1

}
rtrimd = true
}
return false
})

n := len(k)
if n == 0 {
return "", ErrKeyIsEmpty
if len(key) == 0 {
return "", ErrKeyHasIllegalChar
}

for i := 0; i < n; {
ki := k[i]
if unicode.IsNumber(rune(key[0])) {
return "", ErrKeyPrefix
}

if ki < utf8RuneSelf {
i++
if keyIllegalChars[ki] == 1 {
return "", ErrKeyHasIllegalChar
}
if unicodeIsControl(rune(ki)) {
return "", ErrKeyHasControlChar
}
continue
}
x := utf8first[ki]
if x == xx {
return "", ErrKeyHasIllegalStarterByte
ckey := key
for len(ckey) > 0 {
c, size := utf8.DecodeRuneInString(ckey)
ckey = ckey[size:]
if unicode.IsControl(c) {
return "", ErrKeyHasControlChar
}

size := int(x & 7)
if i+size > n {
return "", ErrKeyNotValidUTF8
if !unicode.IsPrint(c) {
return "", ErrKeyHasNonPrintChar
}
accept := utf8AcceptRanges[x>>4]
if c := k[i+1]; c < accept.lo || accept.hi < c {
return "", ErrKeyOutOfRange
} else if size == 2 {
r := rune(k[i]&mask2)<<6 | rune(k[i+1]&maskx)
if !unicodeIsPrint(r) {
return "", ErrKeyHasNonPrintChar
}
} else if c := k[i+2]; c < locb || hicb < c {
return "", ErrKeyNotValidUTF8
} else if size == 3 {
r := rune(k[i]&mask3)<<12 | rune(k[i+1]&maskx)<<6 | rune(k[i+2]&maskx)
if !unicodeIsPrint(r) {
return "", ErrKeyHasNonPrintChar
}
} else if c := k[i+3]; c < locb || hicb < c {
return "", ErrKeyOutOfRange
} else if size == 4 {
r := rune(k[i]&mask4)<<18 | rune(k[i+1]&maskx)<<12 | rune(k[i+2]&maskx)<<6 | rune(k[i+3]&maskx)
if !unicodeIsPrint(r) {
return "", ErrKeyHasNonPrintChar
}
if c < 256 && (keyIllegalChars[c] == 1) {
return "", ErrKeyHasIllegalChar
}
i += size
}

return k, nil
return key, nil
}
81 changes: 0 additions & 81 deletions pkg/vars/key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ package vars_test

import (
"errors"
"strings"
"testing"
"unicode"
"unicode/utf8"

"github.com/happy-sdk/happy/pkg/vars"
)
Expand All @@ -28,54 +25,6 @@ var (
}
)

// parseKeyStd is parseKey equivalent used in tests.
// IMPORTANT! This implementations should reflect optimal key parsing
// done with std libraries so that we can have adequate
// benchmark results for our own implementation.
func parseKeyStd(str string) (key string, err error) {
if len(str) == 0 {
return "", vars.ErrKeyIsEmpty
}

if !utf8.ValidString(str) {
return "", vars.ErrKeyNotValidUTF8
}

// remove most outer trimmable characters
key = strings.TrimFunc(str, func(c rune) bool {
if c < 256 {
return keyAutoTrimableChars[c] == 1

}
return false
})

if len(key) == 0 {
return "", vars.ErrKeyHasIllegalChar
}

if unicode.IsNumber(rune(key[0])) {
return "", vars.ErrKeyPrefix
}

ckey := key
for len(ckey) > 0 {
c, size := utf8.DecodeRuneInString(ckey)
ckey = ckey[size:]
if unicode.IsControl(c) {
return "", vars.ErrKeyHasControlChar
}

if !unicode.IsPrint(c) {
return "", vars.ErrKeyHasNonPrintChar
}
if c < 256 && (keyIllegalChars[c] == 1) {
return "", vars.ErrKeyHasIllegalChar
}
}
return key, nil
}

type keyTest struct {
Key string
Want string
Expand Down Expand Up @@ -169,18 +118,6 @@ func getKeyTests() []keyTest {
}
}

func TestParseKeyStdTest(t *testing.T) {
for _, test := range getKeyTests() {
key, err := parseKeyStd(test.Key)
if test.Want != key {
t.Errorf("in(%s) want(%s) got(%s) err(%v)", test.Key, test.Want, key, err)
}
if !errors.Is(err, test.Err) {
t.Errorf("in(%s) want err(%s) got err(%v)", test.Key, test.Want, err)
}
}
}

func TestParseKey(t *testing.T) {
for _, test := range getKeyTests() {
// check that key set is correct
Expand All @@ -195,21 +132,3 @@ func TestParseKey(t *testing.T) {
}
}
}

func FuzzVariableKeys(f *testing.F) {
for _, test := range getKeyTests() {
f.Add(test.Key)
}
f.Fuzz(func(t *testing.T, arg string) {
klib, errlib := vars.ParseKey(arg)
kstd, errstd := parseKeyStd(arg)

if klib != kstd {
t.Errorf("arg(%s) parsed keys do not match std(%s) != lib(%s)", arg, kstd, klib)
}

if (errlib != nil && errstd == nil) || errlib == nil && errstd != nil {
t.Fatalf("arg(%s) lib error(%v) not like std error(%v)", arg, errlib, errstd)
}
})
}

0 comments on commit 5607003

Please sign in to comment.