1// Copyright 2019 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package android
16
17import (
18	"testing"
19	"time"
20)
21
22func TestOncePer_Once(t *testing.T) {
23	once := OncePer{}
24	key := NewOnceKey("key")
25
26	a := once.Once(key, func() interface{} { return "a" }).(string)
27	b := once.Once(key, func() interface{} { return "b" }).(string)
28
29	if a != "a" {
30		t.Errorf(`first call to Once should return "a": %q`, a)
31	}
32
33	if b != "a" {
34		t.Errorf(`second call to Once with the same key should return "a": %q`, b)
35	}
36}
37
38func TestOncePer_Once_wait(t *testing.T) {
39	once := OncePer{}
40	key := NewOnceKey("key")
41
42	ch := make(chan bool)
43
44	go once.Once(key, func() interface{} { close(ch); time.Sleep(100 * time.Millisecond); return "foo" })
45	<-ch
46	a := once.Once(key, func() interface{} { return "bar" }).(string)
47
48	if a != "foo" {
49		t.Errorf("expect %q, got %q", "foo", a)
50	}
51}
52
53func TestOncePer_Get(t *testing.T) {
54	once := OncePer{}
55	key := NewOnceKey("key")
56
57	a := once.Once(key, func() interface{} { return "a" }).(string)
58	b := once.Get(key).(string)
59
60	if a != "a" {
61		t.Errorf(`first call to Once should return "a": %q`, a)
62	}
63
64	if b != "a" {
65		t.Errorf(`Get with the same key should return "a": %q`, b)
66	}
67}
68
69func TestOncePer_Get_panic(t *testing.T) {
70	once := OncePer{}
71	key := NewOnceKey("key")
72
73	defer func() {
74		p := recover()
75
76		if p == nil {
77			t.Error("call to Get for unused key should panic")
78		}
79	}()
80
81	once.Get(key)
82}
83
84func TestOncePer_Get_wait(t *testing.T) {
85	once := OncePer{}
86	key := NewOnceKey("key")
87
88	ch := make(chan bool)
89
90	go once.Once(key, func() interface{} { close(ch); time.Sleep(100 * time.Millisecond); return "foo" })
91	<-ch
92	a := once.Get(key).(string)
93
94	if a != "foo" {
95		t.Errorf("expect %q, got %q", "foo", a)
96	}
97}
98
99func TestOncePer_OnceStringSlice(t *testing.T) {
100	once := OncePer{}
101	key := NewOnceKey("key")
102
103	a := once.OnceStringSlice(key, func() []string { return []string{"a"} })
104	b := once.OnceStringSlice(key, func() []string { return []string{"a"} })
105
106	if a[0] != "a" {
107		t.Errorf(`first call to OnceStringSlice should return ["a"]: %q`, a)
108	}
109
110	if b[0] != "a" {
111		t.Errorf(`second call to OnceStringSlice with the same key should return ["a"]: %q`, b)
112	}
113}
114
115func TestOncePer_Once2StringSlice(t *testing.T) {
116	once := OncePer{}
117	key := NewOnceKey("key")
118
119	a, b := once.Once2StringSlice(key, func() ([]string, []string) { return []string{"a"}, []string{"b"} })
120	c, d := once.Once2StringSlice(key, func() ([]string, []string) { return []string{"c"}, []string{"d"} })
121
122	if a[0] != "a" || b[0] != "b" {
123		t.Errorf(`first call to Once2StringSlice should return ["a"], ["b"]: %q, %q`, a, b)
124	}
125
126	if c[0] != "a" || d[0] != "b" {
127		t.Errorf(`second call to Once2StringSlice with the same key should return ["a"], ["b"]: %q, %q`, c, d)
128	}
129}
130
131func TestNewOnceKey(t *testing.T) {
132	once := OncePer{}
133	key1 := NewOnceKey("key")
134	key2 := NewOnceKey("key")
135
136	a := once.Once(key1, func() interface{} { return "a" }).(string)
137	b := once.Once(key2, func() interface{} { return "b" }).(string)
138
139	if a != "a" {
140		t.Errorf(`first call to Once should return "a": %q`, a)
141	}
142
143	if b != "b" {
144		t.Errorf(`second call to Once with the NewOnceKey from same string should return "b": %q`, b)
145	}
146}
147
148func TestNewCustomOnceKey(t *testing.T) {
149	type key struct {
150		key string
151	}
152	once := OncePer{}
153	key1 := NewCustomOnceKey(key{"key"})
154	key2 := NewCustomOnceKey(key{"key"})
155
156	a := once.Once(key1, func() interface{} { return "a" }).(string)
157	b := once.Once(key2, func() interface{} { return "b" }).(string)
158
159	if a != "a" {
160		t.Errorf(`first call to Once should return "a": %q`, a)
161	}
162
163	if b != "a" {
164		t.Errorf(`second call to Once with the NewCustomOnceKey from equal key should return "a": %q`, b)
165	}
166}
167
168func TestOncePerReentrant(t *testing.T) {
169	once := OncePer{}
170	key1 := NewOnceKey("key")
171	key2 := NewOnceKey("key")
172
173	a := once.Once(key1, func() interface{} { return once.Once(key2, func() interface{} { return "a" }) })
174	if a != "a" {
175		t.Errorf(`reentrant Once should return "a": %q`, a)
176	}
177}
178
179// Test that a recovered panic in a Once function doesn't deadlock
180func TestOncePerPanic(t *testing.T) {
181	once := OncePer{}
182	key := NewOnceKey("key")
183
184	ch := make(chan interface{})
185
186	var a interface{}
187
188	go func() {
189		defer func() {
190			ch <- recover()
191		}()
192
193		a = once.Once(key, func() interface{} {
194			panic("foo")
195		})
196	}()
197
198	p := <-ch
199
200	if p.(string) != "foo" {
201		t.Errorf(`expected panic with "foo", got %#v`, p)
202	}
203
204	if a != nil {
205		t.Errorf(`expected a to be nil, got %#v`, a)
206	}
207
208	// If the call to Once that panicked leaves the key in a bad state this will deadlock
209	b := once.Once(key, func() interface{} {
210		return "bar"
211	})
212
213	// The second call to Once should return nil inserted by the first call that panicked.
214	if b != nil {
215		t.Errorf(`expected b to be nil, got %#v`, b)
216	}
217}
218