| // Copyright 2020 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| //go:build goexperiment.jsonv2 |
| |
| package json |
| |
| import ( |
| "fmt" |
| "reflect" |
| "testing" |
| "unicode" |
| ) |
| |
| var equalFoldTestdata = []struct { |
| in1, in2 string |
| want bool |
| }{ |
| {"", "", true}, |
| {"abc", "abc", true}, |
| {"ABcd", "ABcd", true}, |
| {"123abc", "123ABC", true}, |
| {"_1_2_-_3__--a-_-b-c-", "123ABC", true}, |
| {"αβδ", "ΑΒΔ", true}, |
| {"abc", "xyz", false}, |
| {"abc", "XYZ", false}, |
| {"abcdefghijk", "abcdefghijX", false}, |
| {"abcdefghijk", "abcdefghij\u212A", true}, |
| {"abcdefghijK", "abcdefghij\u212A", true}, |
| {"abcdefghijkz", "abcdefghij\u212Ay", false}, |
| {"abcdefghijKz", "abcdefghij\u212Ay", false}, |
| {"1", "2", false}, |
| {"utf-8", "US-ASCII", false}, |
| {"hello, world!", "hello, world!", true}, |
| {"hello, world!", "Hello, World!", true}, |
| {"hello, world!", "HELLO, WORLD!", true}, |
| {"hello, world!", "jello, world!", false}, |
| {"γειά, κόσμε!", "γειά, κόσμε!", true}, |
| {"γειά, κόσμε!", "Γειά, Κόσμε!", true}, |
| {"γειά, κόσμε!", "ΓΕΙΆ, ΚΌΣΜΕ!", true}, |
| {"γειά, κόσμε!", "ΛΕΙΆ, ΚΌΣΜΕ!", false}, |
| {"AESKey", "aesKey", true}, |
| {"γειά, κόσμε!", "Γ\xce_\xb5ιά, Κόσμε!", false}, |
| {"aeskey", "AESKEY", true}, |
| {"AESKEY", "aes_key", true}, |
| {"aes_key", "AES_KEY", true}, |
| {"AES_KEY", "aes-key", true}, |
| {"aes-key", "AES-KEY", true}, |
| {"AES-KEY", "aesKey", true}, |
| {"aesKey", "AesKey", true}, |
| {"AesKey", "AESKey", true}, |
| {"AESKey", "aeskey", true}, |
| {"DESKey", "aeskey", false}, |
| {"AES Key", "aeskey", false}, |
| {"aes﹏key", "aeskey", false}, // Unicode underscore not handled |
| {"aes〰key", "aeskey", false}, // Unicode dash not handled |
| } |
| |
| func TestEqualFold(t *testing.T) { |
| for _, tt := range equalFoldTestdata { |
| got := equalFold([]byte(tt.in1), []byte(tt.in2)) |
| if got != tt.want { |
| t.Errorf("equalFold(%q, %q) = %v, want %v", tt.in1, tt.in2, got, tt.want) |
| } |
| } |
| } |
| |
| func equalFold(x, y []byte) bool { |
| return string(foldName(x)) == string(foldName(y)) |
| } |
| |
| func TestFoldRune(t *testing.T) { |
| if testing.Short() { |
| t.Skip() |
| } |
| |
| var foldSet []rune |
| for r := range rune(unicode.MaxRune + 1) { |
| // Derive all runes that are all part of the same fold set. |
| foldSet = foldSet[:0] |
| for r0 := r; r != r0 || len(foldSet) == 0; r = unicode.SimpleFold(r) { |
| foldSet = append(foldSet, r) |
| } |
| |
| // Normalized form of each rune in a foldset must be the same and |
| // also be within the set itself. |
| var withinSet bool |
| rr0 := foldRune(foldSet[0]) |
| for _, r := range foldSet { |
| withinSet = withinSet || rr0 == r |
| rr := foldRune(r) |
| if rr0 != rr { |
| t.Errorf("foldRune(%q) = %q, want %q", r, rr, rr0) |
| } |
| } |
| if !withinSet { |
| t.Errorf("foldRune(%q) = %q not in fold set %q", foldSet[0], rr0, string(foldSet)) |
| } |
| } |
| } |
| |
| // TestBenchmarkUnmarshalUnknown unmarshals an unknown field into a struct with |
| // varying number of fields. Since the unknown field does not directly match |
| // any known field by name, it must fall back on case-insensitive matching. |
| func TestBenchmarkUnmarshalUnknown(t *testing.T) { |
| in := []byte(`{"NameUnknown":null}`) |
| for _, n := range []int{1, 2, 5, 10, 20, 50, 100} { |
| unmarshal := Unmarshal |
| |
| var fields []reflect.StructField |
| for i := range n { |
| fields = append(fields, reflect.StructField{ |
| Name: fmt.Sprintf("Name%d", i), |
| Type: T[int](), |
| Tag: `json:",case:ignore"`, |
| }) |
| } |
| out := reflect.New(reflect.StructOf(fields)).Interface() |
| |
| t.Run(fmt.Sprintf("N%d", n), func(t *testing.T) { |
| if err := unmarshal(in, out); err != nil { |
| t.Fatalf("Unmarshal error: %v", err) |
| } |
| }) |
| } |
| } |