Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor pkg test helper functions #1678

Merged
merged 29 commits into from
Jun 2, 2022
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
829b460
refactor charset helper func
kevindiu May 25, 2022
743b8b6
refactor vector helper func
kevindiu May 25, 2022
05f872a
refactor request helper func
kevindiu May 25, 2022
7e374aa
add missing files
kevindiu May 25, 2022
847bbe2
move charset to conv
kevindiu May 26, 2022
a3dc388
return error from helper func
kevindiu May 26, 2022
7691ea4
refactor conv helper func
kevindiu May 30, 2022
1cddad7
refactor fill() and implement buildIndex()
kevindiu May 31, 2022
90be937
fix comment
kevindiu May 31, 2022
0796dc5
refactor convertXXX
kevindiu May 31, 2022
b5759bd
refactor search test func
kevindiu May 31, 2022
6964a0e
refactor beforeFunc test func to use buildIndex
kevindiu Jun 1, 2022
9cd164c
:robot: Update license headers / Format go codes and yaml files
vdaas-ci Jun 1, 2022
7037415
Revert ":robot: Update license headers / Format go codes and yaml files"
kevindiu Jun 1, 2022
15ea532
format code
kevindiu Jun 1, 2022
1343782
fix comment
kevindiu Jun 1, 2022
b6a9057
implement test for helper functions
kevindiu Jun 1, 2022
61d76d5
add comments to helper functions
kevindiu Jun 1, 2022
928b4c8
implement conv test
kevindiu Jun 1, 2022
9eb32fc
fix golangci warning
kevindiu Jun 1, 2022
c203493
fix comment
kevindiu Jun 1, 2022
c85b54c
fix golangci warning
kevindiu Jun 2, 2022
5ad9c5a
split encode()
kevindiu Jun 2, 2022
b6591a4
implement boundary value test for vector/gen
kevindiu Jun 2, 2022
f60334a
use io instead of ioutil package
kevindiu Jun 2, 2022
dd4d4f7
Update internal/conv/conv_test.go
kevindiu Jun 2, 2022
be8dd0b
add boundary tests
kevindiu Jun 2, 2022
082ac19
fix test error
kevindiu Jun 2, 2022
c477b85
add more boundary tests
kevindiu Jun 2, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions internal/conv/conv.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@
package conv

import (
"io"
vankichi marked this conversation as resolved.
Show resolved Hide resolved
"reflect"
"strings"
"unsafe"

"golang.org/x/text/encoding/japanese"
"golang.org/x/text/transform"
)

// Btoa converts from byte slice to string.
Expand Down Expand Up @@ -48,3 +53,21 @@ func F32stos(fs []float32) (s string) {
(*(*int)(unsafe.Pointer(uintptr(addr) + uintptr(16)))) = lf
return Btoa(buf)
}

// Utf8ToSjis converts a UTF8 string to sjis string.
func Utf8ToSjis(s string) (string, error) {
return encode(strings.NewReader(s), japanese.ShiftJIS.NewEncoder())
}

// Utf8ToEucjp converts a UTF8 string to eucjp string.
func Utf8ToEucjp(s string) (string, error) {
return encode(strings.NewReader(s), japanese.EUCJP.NewEncoder())
}

func encode(r io.Reader, t transform.Transformer) (string, error) {
b, err := io.ReadAll(transform.NewReader(r, t))
if err != nil {
return "", err
}
return string(b), nil
}
221 changes: 221 additions & 0 deletions internal/conv/conv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,16 @@
package conv

import (
"io"
"reflect"
"strings"
"testing"
"testing/iotest"

"github.com/vdaas/vald/internal/errors"
"github.com/vdaas/vald/internal/test/goleak"
"golang.org/x/text/encoding/japanese"
"golang.org/x/text/transform"
)

var testData = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
Expand Down Expand Up @@ -236,3 +241,219 @@ func TestF32stos(t *testing.T) {
})
}
}

func TestUtf8ToSjis(t *testing.T) {
type args struct {
s string
}
type want struct {
want string
err error
}
type test struct {
name string
args args
want want
checkFunc func(want, string, error) error
beforeFunc func(args)
afterFunc func(args)
}
defaultCheckFunc := func(w want, got string, err error) error {
if !errors.Is(err, w.err) {
return errors.Errorf("got_error: \"%#v\",\n\t\t\t\twant: \"%#v\"", err, w.err)
}
if !reflect.DeepEqual(got, w.want) {
return errors.Errorf("got: \"%#v\",\n\t\t\t\twant: \"%#v\"", got, w.want)
}
return nil
}
tests := []test{
{
name: "return sjis string from UTF8 string",
args: args{
s: "こんにちは",
},
want: want{
want: "\x82\xb1\x82\xf1\x82ɂ\xbf\x82\xcd",
},
},
Comment on lines +271 to +279
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you please add an error case at least?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{
name: "return empty string when the UTF8 string is empty",
args: args{
s: "",
},
want: want{
want: "",
},
},
}

for _, tc := range tests {
test := tc
t.Run(test.name, func(tt *testing.T) {
tt.Parallel()
defer goleak.VerifyNone(tt, goleak.IgnoreCurrent())
if test.beforeFunc != nil {
test.beforeFunc(test.args)
}
if test.afterFunc != nil {
defer test.afterFunc(test.args)
}
checkFunc := test.checkFunc
if test.checkFunc == nil {
checkFunc = defaultCheckFunc
}

got, err := Utf8ToSjis(test.args.s)
if err := checkFunc(test.want, got, err); err != nil {
tt.Errorf("error = %v", err)
}
})
}
}

func TestUtf8ToEucjp(t *testing.T) {
type args struct {
s string
}
type want struct {
want string
err error
}
type test struct {
name string
args args
want want
checkFunc func(want, string, error) error
beforeFunc func(args)
afterFunc func(args)
}
defaultCheckFunc := func(w want, got string, err error) error {
if !errors.Is(err, w.err) {
return errors.Errorf("got_error: \"%#v\",\n\t\t\t\twant: \"%#v\"", err, w.err)
}
if !reflect.DeepEqual(got, w.want) {
return errors.Errorf("got: \"%#v\",\n\t\t\t\twant: \"%#v\"", got, w.want)
}
return nil
}
tests := []test{
{
name: "return eucjp string from UTF8 string",
args: args{
s: "こんにちは",
},
want: want{
want: "\xa4\xb3\xa4\xf3\xa4ˤ\xc1\xa4\xcf",
},
},
Comment on lines +341 to +349
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you please add an error case at least?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry I couldn't think of any error case for this test, do you have any idea?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just idea, so it may enable for test to split function like below and to use iotest.ErrReader in testing/iotest package.

func utf8ToSjis(r io.Reader) (string, error) {
	b, err := io.ReadAll(transform.NewReader(r, japanese.ShiftJIS.NewEncoder()))
	if err != nil {
		return "", err
	}
	return string(b), nil
}

// Utf8ToSjis converts a UTF8 string to sjis string.
func Utf8ToSjis(s string) (string, error) {
	return utf8ToSjis(strings.NewReader(s))
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed by spliting the ecode()
changes: 5ad9c5a

{
name: "return empty string when the UTF8 string is empty",
args: args{
s: "",
},
want: want{
want: "",
},
},
}

for _, tc := range tests {
test := tc
t.Run(test.name, func(tt *testing.T) {
tt.Parallel()
defer goleak.VerifyNone(tt, goleak.IgnoreCurrent())
if test.beforeFunc != nil {
test.beforeFunc(test.args)
}
if test.afterFunc != nil {
defer test.afterFunc(test.args)
}
checkFunc := test.checkFunc
if test.checkFunc == nil {
checkFunc = defaultCheckFunc
}

got, err := Utf8ToEucjp(test.args.s)
if err := checkFunc(test.want, got, err); err != nil {
tt.Errorf("error = %v", err)
}
})
}
}

func Test_encode(t *testing.T) {
type args struct {
r io.Reader
t transform.Transformer
}
type want struct {
want string
err error
}
type test struct {
name string
args args
want want
checkFunc func(want, string, error) error
beforeFunc func(args)
afterFunc func(args)
}
defaultCheckFunc := func(w want, got string, err error) error {
if !errors.Is(err, w.err) {
return errors.Errorf("got_error: \"%#v\",\n\t\t\t\twant: \"%#v\"", err, w.err)
}
if !reflect.DeepEqual(got, w.want) {
return errors.Errorf("got: \"%#v\",\n\t\t\t\twant: \"%#v\"", got, w.want)
}
return nil
}
tests := []test{
{
name: "success to encode string",
args: args{
r: strings.NewReader("こんにちは"),
t: japanese.EUCJP.NewEncoder(),
},
want: want{
want: "\xa4\xb3\xa4\xf3\xa4ˤ\xc1\xa4\xcf",
},
},
func() test {
err := errors.New("invalid reader")
return test{
name: "fail to encode string",
args: args{
r: iotest.ErrReader(err),
t: japanese.EUCJP.NewEncoder(),
},
want: want{
err: err,
},
}
}(),
}

for _, tc := range tests {
test := tc
t.Run(test.name, func(tt *testing.T) {
tt.Parallel()
defer goleak.VerifyNone(tt, goleak.IgnoreCurrent())
if test.beforeFunc != nil {
test.beforeFunc(test.args)
}
if test.afterFunc != nil {
defer test.afterFunc(test.args)
}
checkFunc := test.checkFunc
if test.checkFunc == nil {
checkFunc = defaultCheckFunc
}

got, err := encode(test.args.r, test.args.t)
if err := checkFunc(test.want, got, err); err != nil {
tt.Errorf("error = %v", err)
}
})
}
}
18 changes: 18 additions & 0 deletions internal/test/data/request/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// Copyright (C) 2019-2022 vdaas.org vald team <vald@vdaas.org>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

// Package request provides functions to generate proto request for testing
package request
77 changes: 77 additions & 0 deletions internal/test/data/request/insert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//
kevindiu marked this conversation as resolved.
Show resolved Hide resolved
// Copyright (C) 2019-2022 vdaas.org vald team <vald@vdaas.org>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package request
kevindiu marked this conversation as resolved.
Show resolved Hide resolved
kevindiu marked this conversation as resolved.
Show resolved Hide resolved

import (
"strconv"

"github.com/vdaas/vald/apis/grpc/v1/payload"
"github.com/vdaas/vald/internal/test/data/vector"
)

type ObjectType int

const (
Uint8 ObjectType = iota
Float
)

func GenMultiInsertReq(t ObjectType, dist vector.Distribution, num int, dim int, cfg *payload.Insert_Config) (*payload.Insert_MultiRequest, error) {
var vecs [][]float32
var err error
switch t {
case Float:
vecs, err = vector.GenF32Vec(dist, num, dim)
case Uint8:
vecs, err = vector.GenUint8Vec(dist, num, dim)
}
if err != nil {
return nil, err
}

req := &payload.Insert_MultiRequest{
Requests: make([]*payload.Insert_Request, num),
}
for i, vec := range vecs {
req.Requests[i] = &payload.Insert_Request{
Vector: &payload.Object_Vector{
Id: "uuid-" + strconv.Itoa(i+1),
Vector: vec,
},
Config: cfg,
}
}

return req, nil
}

// generate MultiInsert request with the same vector
func GenSameVecMultiInsertReq(num int, vec []float32, cfg *payload.Insert_Config) *payload.Insert_MultiRequest {
req := &payload.Insert_MultiRequest{
Requests: make([]*payload.Insert_Request, num),
}
for i := 0; i < num; i++ {
req.Requests[i] = &payload.Insert_Request{
Vector: &payload.Object_Vector{
Id: "uuid-" + strconv.Itoa(i+1),
Vector: vec,
},
Config: cfg,
}
}

return req
}
Loading