@@ -7,6 +7,7 @@ package sort_test
7
7
import (
8
8
"runtime"
9
9
. "sort"
10
+ stringspkg "strings"
10
11
"testing"
11
12
)
12
13
@@ -57,6 +58,80 @@ func TestSearch(t *testing.T) {
57
58
}
58
59
}
59
60
61
+ func TestFind (t * testing.T ) {
62
+ str1 := []string {"foo" }
63
+ str2 := []string {"ab" , "ca" }
64
+ str3 := []string {"mo" , "qo" , "vo" }
65
+ str4 := []string {"ab" , "ad" , "ca" , "xy" }
66
+
67
+ // slice with repeating elements
68
+ strRepeats := []string {"ba" , "ca" , "da" , "da" , "da" , "ka" , "ma" , "ma" , "ta" }
69
+
70
+ // slice with all element equal
71
+ strSame := []string {"xx" , "xx" , "xx" }
72
+
73
+ tests := []struct {
74
+ data []string
75
+ target string
76
+ wantPos int
77
+ wantFound bool
78
+ }{
79
+ {[]string {}, "foo" , 0 , false },
80
+ {[]string {}, "" , 0 , false },
81
+
82
+ {str1 , "foo" , 0 , true },
83
+ {str1 , "bar" , 0 , false },
84
+ {str1 , "zx" , 1 , false },
85
+
86
+ {str2 , "aa" , 0 , false },
87
+ {str2 , "ab" , 0 , true },
88
+ {str2 , "ad" , 1 , false },
89
+ {str2 , "ca" , 1 , true },
90
+ {str2 , "ra" , 2 , false },
91
+
92
+ {str3 , "bb" , 0 , false },
93
+ {str3 , "mo" , 0 , true },
94
+ {str3 , "nb" , 1 , false },
95
+ {str3 , "qo" , 1 , true },
96
+ {str3 , "tr" , 2 , false },
97
+ {str3 , "vo" , 2 , true },
98
+ {str3 , "xr" , 3 , false },
99
+
100
+ {str4 , "aa" , 0 , false },
101
+ {str4 , "ab" , 0 , true },
102
+ {str4 , "ac" , 1 , false },
103
+ {str4 , "ad" , 1 , true },
104
+ {str4 , "ax" , 2 , false },
105
+ {str4 , "ca" , 2 , true },
106
+ {str4 , "cc" , 3 , false },
107
+ {str4 , "dd" , 3 , false },
108
+ {str4 , "xy" , 3 , true },
109
+ {str4 , "zz" , 4 , false },
110
+
111
+ {strRepeats , "da" , 2 , true },
112
+ {strRepeats , "db" , 5 , false },
113
+ {strRepeats , "ma" , 6 , true },
114
+ {strRepeats , "mb" , 8 , false },
115
+
116
+ {strSame , "xx" , 0 , true },
117
+ {strSame , "ab" , 0 , false },
118
+ {strSame , "zz" , 3 , false },
119
+ }
120
+
121
+ for _ , tt := range tests {
122
+ t .Run (tt .target , func (t * testing.T ) {
123
+ cmp := func (i int ) int {
124
+ return stringspkg .Compare (tt .target , tt .data [i ])
125
+ }
126
+
127
+ pos , found := Find (len (tt .data ), cmp )
128
+ if pos != tt .wantPos || found != tt .wantFound {
129
+ t .Errorf ("Find got (%v, %v), want (%v, %v)" , pos , found , tt .wantPos , tt .wantFound )
130
+ }
131
+ })
132
+ }
133
+ }
134
+
60
135
// log2 computes the binary logarithm of x, rounded up to the next integer.
61
136
// (log2(0) == 0, log2(1) == 0, log2(2) == 1, log2(3) == 2, etc.)
62
137
func log2 (x int ) int {
@@ -158,3 +233,34 @@ func TestSearchExhaustive(t *testing.T) {
158
233
}
159
234
}
160
235
}
236
+
237
+ // Abstract exhaustive test for Find.
238
+ func TestFindExhaustive (t * testing.T ) {
239
+ // Test Find for different sequence sizes and search targets.
240
+ // For each size, we have a (unmaterialized) sequence of integers:
241
+ // 2,4...size*2
242
+ // And we're looking for every possible integer between 1 and size*2 + 1.
243
+ for size := 0 ; size <= 100 ; size ++ {
244
+ for x := 1 ; x <= size * 2 + 1 ; x ++ {
245
+ var wantFound bool
246
+ var wantPos int
247
+
248
+ cmp := func (i int ) int {
249
+ // Encodes the unmaterialized sequence with elem[i] == (i+1)*2
250
+ return x - (i + 1 )* 2
251
+ }
252
+ pos , found := Find (size , cmp )
253
+
254
+ if x % 2 == 0 {
255
+ wantPos = x / 2 - 1
256
+ wantFound = true
257
+ } else {
258
+ wantPos = x / 2
259
+ wantFound = false
260
+ }
261
+ if found != wantFound || pos != wantPos {
262
+ t .Errorf ("Find(%d, %d): got (%v, %v), want (%v, %v)" , size , x , pos , found , wantPos , wantFound )
263
+ }
264
+ }
265
+ }
266
+ }
0 commit comments