vitess.io/vitess@v0.16.2/go/mysql/collations/integration/helpers_test.go (about)

     1  /*
     2  Copyright 2021 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package integration
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/hex"
    22  	"fmt"
    23  	"io"
    24  	"strings"
    25  	"testing"
    26  
    27  	"github.com/stretchr/testify/assert"
    28  	"github.com/stretchr/testify/require"
    29  
    30  	"vitess.io/vitess/go/mysql"
    31  	"vitess.io/vitess/go/mysql/collations"
    32  	"vitess.io/vitess/go/mysql/collations/internal/charset"
    33  	"vitess.io/vitess/go/mysql/collations/remote"
    34  	"vitess.io/vitess/go/sqltypes"
    35  )
    36  
    37  type testweight struct {
    38  	collation string
    39  	input     []byte
    40  }
    41  
    42  type testcmp struct {
    43  	collation   string
    44  	left, right []byte
    45  }
    46  
    47  func testRemoteWeights(t *testing.T, golden io.Writer, cases []testweight) {
    48  	conn := mysqlconn(t)
    49  	defer conn.Close()
    50  
    51  	for _, tc := range cases {
    52  		t.Run(tc.collation, func(t *testing.T) {
    53  			local := collations.Local().LookupByName(tc.collation)
    54  			remote := remote.NewCollation(conn, tc.collation)
    55  			localResult := local.WeightString(nil, tc.input, 0)
    56  			remoteResult := remote.WeightString(nil, tc.input, 0)
    57  
    58  			if err := remote.LastError(); err != nil {
    59  				t.Fatalf("remote collation failed: %v", err)
    60  			}
    61  			assert.True(t, bytes.Equal(localResult, remoteResult), "expected WEIGHT_STRING(%#v) = %#v (got %#v)", tc.input, remoteResult, localResult)
    62  
    63  			if golden != nil {
    64  				fmt.Fprintf(golden, "{\n\tcollation: %q,\n\texpected: %#v,\n},\n", tc.collation, remoteResult)
    65  			}
    66  		})
    67  	}
    68  }
    69  
    70  func testRemoteComparison(t *testing.T, golden io.Writer, cases []testcmp) {
    71  	normalizecmp := func(res int) int {
    72  		if res < 0 {
    73  			return -1
    74  		}
    75  		if res > 0 {
    76  			return 1
    77  		}
    78  		return 0
    79  	}
    80  
    81  	conn := mysqlconn(t)
    82  	defer conn.Close()
    83  
    84  	for _, tc := range cases {
    85  		t.Run(tc.collation, func(t *testing.T) {
    86  			local := collations.Local().LookupByName(tc.collation)
    87  			remote := remote.NewCollation(conn, tc.collation)
    88  			localResult := normalizecmp(local.Collate(tc.left, tc.right, false))
    89  			remoteResult := remote.Collate(tc.left, tc.right, false)
    90  
    91  			if err := remote.LastError(); err != nil {
    92  				t.Fatalf("remote collation failed: %v", err)
    93  			}
    94  			assert.Equal(t, remoteResult, localResult, "expected STRCMP(%q, %q) = %d (got %d)", string(tc.left), string(tc.right), remoteResult, localResult)
    95  
    96  			if golden != nil {
    97  				fmt.Fprintf(golden, "{\n\tcollation: %q,\n\tleft: %#v,\n\tright: %#v,\n\texpected: %d,\n},\n",
    98  					tc.collation, tc.left, tc.right, remoteResult)
    99  			}
   100  		})
   101  	}
   102  }
   103  
   104  func verifyTranscoding(t *testing.T, local collations.Collation, remote *remote.Collation, text []byte) []byte {
   105  	transRemote, err := charset.ConvertFromUTF8(nil, remote.Charset(), text)
   106  	require.NoError(t, err, "remote transcoding failed: %v", err)
   107  
   108  	transLocal, _ := charset.ConvertFromUTF8(nil, local.Charset(), text)
   109  	require.True(t, bytes.Equal(transLocal, transRemote), "transcoding mismatch with %s (%d, charset: %s)\ninput:\n%s\nremote:\n%s\nlocal:\n%s\n", local.Name(), local.ID(), local.Charset().Name(),
   110  		hex.Dump(text), hex.Dump(transRemote), hex.Dump(transLocal))
   111  
   112  	return transLocal
   113  }
   114  
   115  func verifyWeightString(t *testing.T, local collations.Collation, remote *remote.Collation, text []byte) {
   116  	localResult := local.WeightString(nil, text, 0)
   117  	remoteResult := remote.WeightString(nil, text, 0)
   118  
   119  	if err := remote.LastError(); err != nil {
   120  		t.Fatalf("remote collation failed: %v", err)
   121  	}
   122  
   123  	if len(remoteResult) == 0 {
   124  		t.Logf("remote collation %s returned empty string", remote.Name())
   125  		return
   126  	}
   127  
   128  	if !bytes.Equal(localResult, remoteResult) {
   129  		printDebugData(t, []string{
   130  			"strnxfrm",
   131  			"--collation", local.Name(),
   132  			"--input", hex.EncodeToString(text),
   133  		})
   134  		t.Fatalf("WEIGHT_STRING mismatch with collation %s (charset %s)\ninput:\n%s\nremote:\n%s\nlocal:\n%s\ngolden:\n%#v\n",
   135  			local.Name(), local.Charset().Name(), hex.Dump(text), hex.Dump(remoteResult), hex.Dump(localResult), text)
   136  	}
   137  }
   138  
   139  func exec(t *testing.T, conn *mysql.Conn, query string) *sqltypes.Result {
   140  	res, err := conn.ExecuteFetch(query, -1, true)
   141  	require.NoError(t, err, "failed to execute %q: %v", query, err)
   142  
   143  	return res
   144  }
   145  
   146  func GoldenWeightString(t *testing.T, conn *mysql.Conn, collation string, input []byte) []byte {
   147  	coll := remote.NewCollation(conn, collation)
   148  	weightString := coll.WeightString(nil, input, 0)
   149  	if weightString == nil {
   150  		t.Fatal(coll.LastError())
   151  	}
   152  	return weightString
   153  }
   154  
   155  var printDebugData = func(t *testing.T, args []string) {
   156  	t.Logf("debug: colldump %s", strings.Join(args, " "))
   157  }