1// Copyright (C) MongoDB, Inc. 2014-present. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); you may 4// not use this file except in compliance with the License. You may obtain 5// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6// 7// Based on github.com/golang/go by The Go Authors 8// See THIRD-PARTY-NOTICES for original license terms. 9 10package json 11 12import ( 13 "bytes" 14 "strings" 15 "testing" 16 "unicode/utf8" 17) 18 19var foldTests = []struct { 20 fn func(s, t []byte) bool 21 s, t string 22 want bool 23}{ 24 {equalFoldRight, "", "", true}, 25 {equalFoldRight, "a", "a", true}, 26 {equalFoldRight, "", "a", false}, 27 {equalFoldRight, "a", "", false}, 28 {equalFoldRight, "a", "A", true}, 29 {equalFoldRight, "AB", "ab", true}, 30 {equalFoldRight, "AB", "ac", false}, 31 {equalFoldRight, "sbkKc", "ſbKKc", true}, 32 {equalFoldRight, "SbKkc", "ſbKKc", true}, 33 {equalFoldRight, "SbKkc", "ſbKK", false}, 34 {equalFoldRight, "e", "é", false}, 35 {equalFoldRight, "s", "S", true}, 36 37 {simpleLetterEqualFold, "", "", true}, 38 {simpleLetterEqualFold, "abc", "abc", true}, 39 {simpleLetterEqualFold, "abc", "ABC", true}, 40 {simpleLetterEqualFold, "abc", "ABCD", false}, 41 {simpleLetterEqualFold, "abc", "xxx", false}, 42 43 {asciiEqualFold, "a_B", "A_b", true}, 44 {asciiEqualFold, "aa@", "aa`", false}, // verify 0x40 and 0x60 aren't case-equivalent 45} 46 47func TestFold(t *testing.T) { 48 for i, tt := range foldTests { 49 if got := tt.fn([]byte(tt.s), []byte(tt.t)); got != tt.want { 50 t.Errorf("%d. %q, %q = %v; want %v", i, tt.s, tt.t, got, tt.want) 51 } 52 truth := strings.EqualFold(tt.s, tt.t) 53 if truth != tt.want { 54 t.Errorf("strings.EqualFold doesn't agree with case %d", i) 55 } 56 } 57} 58 59func TestFoldAgainstUnicode(t *testing.T) { 60 const bufSize = 5 61 buf1 := make([]byte, 0, bufSize) 62 buf2 := make([]byte, 0, bufSize) 63 var runes []rune 64 for i := 0x20; i <= 0x7f; i++ { 65 runes = append(runes, rune(i)) 66 } 67 runes = append(runes, kelvin, smallLongEss) 68 69 funcs := []struct { 70 name string 71 fold func(s, t []byte) bool 72 letter bool // must be ASCII letter 73 simple bool // must be simple ASCII letter (not 'S' or 'K') 74 }{ 75 { 76 name: "equalFoldRight", 77 fold: equalFoldRight, 78 }, 79 { 80 name: "asciiEqualFold", 81 fold: asciiEqualFold, 82 simple: true, 83 }, 84 { 85 name: "simpleLetterEqualFold", 86 fold: simpleLetterEqualFold, 87 simple: true, 88 letter: true, 89 }, 90 } 91 92 for _, ff := range funcs { 93 for _, r := range runes { 94 if r >= utf8.RuneSelf { 95 continue 96 } 97 if ff.letter && !isASCIILetter(byte(r)) { 98 continue 99 } 100 if ff.simple && (r == 's' || r == 'S' || r == 'k' || r == 'K') { 101 continue 102 } 103 for _, r2 := range runes { 104 buf1 := append(buf1[:0], 'x') 105 buf2 := append(buf2[:0], 'x') 106 buf1 = buf1[:1+utf8.EncodeRune(buf1[1:bufSize], r)] 107 buf2 = buf2[:1+utf8.EncodeRune(buf2[1:bufSize], r2)] 108 buf1 = append(buf1, 'x') 109 buf2 = append(buf2, 'x') 110 want := bytes.EqualFold(buf1, buf2) 111 if got := ff.fold(buf1, buf2); got != want { 112 t.Errorf("%s(%q, %q) = %v; want %v", ff.name, buf1, buf2, got, want) 113 } 114 } 115 } 116 } 117} 118 119func isASCIILetter(b byte) bool { 120 return ('A' <= b && b <= 'Z') || ('a' <= b && b <= 'z') 121} 122