1// Copyright 2015 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4package engine
5
6import (
7	"fmt"
8	"sort"
9	"strings"
10	"testing"
11
12	"github.com/keybase/client/go/libkb"
13	keybase1 "github.com/keybase/client/go/protocol/keybase1"
14)
15
16func makeFave(u1, u2 string) string {
17	return strings.Join([]string{u1, u2}, ",")
18}
19
20func TestFavoriteAdd(t *testing.T) {
21	tc := SetupEngineTest(t, "template")
22	defer tc.Cleanup()
23	u := CreateAndSignupFakeUser(tc, "fav")
24	expectedFaves := newFavorites(u.Username)
25
26	idUI := &FakeIdentifyUI{}
27	fave := makeFave(u.Username, "t_bob")
28	addfav(fave, keybase1.FolderType_PRIVATE, true, idUI, tc, expectedFaves)
29	if !listfav(tc).Equal(*expectedFaves) {
30		t.Errorf("bad favorites")
31	}
32
33	// Add the same share again. The number shouldn't change.
34	addfav(fave, keybase1.FolderType_PRIVATE, true, idUI, tc, nil)
35	if !listfav(tc).Equal(*expectedFaves) {
36		t.Errorf("bad favorites")
37	}
38
39	// Add a public share of the same name, make sure both are represented.
40	addfav(fave, keybase1.FolderType_PUBLIC, true, idUI, tc, expectedFaves)
41	if !listfav(tc).Equal(*expectedFaves) {
42		t.Errorf("bad favorites")
43	}
44}
45
46// Test adding a favorite with a social assertion.
47// Sharing before signup, social assertion user doesn't
48// exist yet.
49func TestFavoriteAddSocial(t *testing.T) {
50	tc := SetupEngineTest(t, "template")
51	defer tc.Cleanup()
52	u := CreateAndSignupFakeUser(tc, "fav")
53	expectedFaves := newFavorites(u.Username)
54
55	idUI := &FakeIdentifyUI{}
56	addfav(fmt.Sprintf("bob@twitter,%s", u.Username), keybase1.FolderType_PRIVATE, true, idUI, tc, expectedFaves)
57	if !listfav(tc).Equal(*expectedFaves) {
58		t.Errorf("bad favorites")
59	}
60
61	if idUI.DisplayTLFCount != 1 {
62		t.Errorf("DisplayTLFCount: %d, expected 1", idUI.DisplayTLFCount)
63	}
64	// There's no way to give invites to a user via API, so the
65	// only case we can test automatically is the user being
66	// out of invites.
67	if !idUI.DisplayTLFArg.Throttled {
68		t.Errorf("DisplayTLFArg.Throttled not set, expected it to be since user has no invites.")
69	}
70	if !idUI.DisplayTLFArg.IsPrivate {
71		t.Errorf("DisplayTLFArg.IsPrivate not set on a private folder")
72	}
73
74	idUI = &FakeIdentifyUI{}
75	// Test adding a favorite when not the creator.  Should not call ui for
76	// displaying tlf + invite.
77	// created flag == false
78	addfav(fmt.Sprintf("bobdog@twitter,%s", u.Username), keybase1.FolderType_PRIVATE, false, idUI, tc, expectedFaves)
79	if newFaves := listfav(tc); !newFaves.Equal(*expectedFaves) {
80		t.Errorf("bad favorites: %s != %s", newFaves, expectedFaves)
81	}
82	if idUI.DisplayTLFCount != 0 {
83		t.Errorf("DisplayTLFCount: %d, expected 0", idUI.DisplayTLFCount)
84	}
85
86	idUI = &FakeIdentifyUI{}
87	// Make sure ui for displaying tlf + invite not called for non-social
88	// assertion TLF.
89	addfav(fmt.Sprintf("%s,t_alice", u.Username), keybase1.FolderType_PRIVATE, true, idUI, tc, expectedFaves)
90	if newFaves := listfav(tc); !newFaves.Equal(*expectedFaves) {
91		t.Errorf("bad favorites: %s != %s", newFaves, expectedFaves)
92	}
93	if idUI.DisplayTLFCount != 0 {
94		t.Errorf("DisplayTLFCount: %d, expected 0", idUI.DisplayTLFCount)
95	}
96
97	idUI = &FakeIdentifyUI{}
98	// Test adding a public favorite with SBS social assertion
99	addfav(fmt.Sprintf("bobdog@twitter,%s", u.Username), keybase1.FolderType_PUBLIC, true, idUI, tc, expectedFaves)
100	if newFaves := listfav(tc); !newFaves.Equal(*expectedFaves) {
101		t.Errorf("bad favorites: %s != %s", newFaves, expectedFaves)
102	}
103	if idUI.DisplayTLFCount != 1 {
104		t.Errorf("DisplayTLFCount: %d, expected 1", idUI.DisplayTLFCount)
105	}
106	if idUI.DisplayTLFArg.IsPrivate {
107		t.Errorf("DisplayTLFArg.IsPrivate set on a public folder")
108	}
109}
110
111func TestFavoriteIgnore(t *testing.T) {
112	tc := SetupEngineTest(t, "template")
113	defer tc.Cleanup()
114	u := CreateAndSignupFakeUser(tc, "fav")
115
116	expectedFaves := newFavorites(u.Username)
117
118	idUI := &FakeIdentifyUI{}
119	addfav(makeFave(u.Username, "t_bob"), keybase1.FolderType_PRIVATE, true, idUI, tc, expectedFaves)
120	addfav(makeFave(u.Username, "t_charlie"), keybase1.FolderType_PRIVATE, true, idUI, tc, expectedFaves)
121	if !listfav(tc).Equal(*expectedFaves) {
122		t.Errorf("bad favorites")
123	}
124	rmfav(makeFave(u.Username, "t_bob"), keybase1.FolderType_PRIVATE, tc, expectedFaves)
125	if !listfav(tc).Equal(*expectedFaves) {
126		t.Errorf("bad favorites")
127	}
128}
129
130func TestFavoriteList(t *testing.T) {
131	tc := SetupEngineTest(t, "template")
132	defer tc.Cleanup()
133	u := CreateAndSignupFakeUser(tc, "fav")
134	expectedFaves := newFavorites(u.Username)
135
136	idUI := &FakeIdentifyUI{}
137	addfav(makeFave(u.Username, "t_charlie"), keybase1.FolderType_PRIVATE, true, idUI, tc, expectedFaves)
138	addfav(makeFave(u.Username, "t_bob"), keybase1.FolderType_PRIVATE, true, idUI, tc, expectedFaves)
139
140	eng := NewFavoriteList(tc.G)
141	m := NewMetaContextForTest(tc)
142	if err := RunEngine2(m, eng); err != nil {
143		t.Fatal(err)
144	}
145	favs := eng.Result().FavoriteFolders
146	if !newFavoritesFromServer(favs).Equal(*expectedFaves) {
147		t.Errorf("bad favorites")
148	}
149}
150
151func addfav(name string, folderType keybase1.FolderType, created bool, idUI libkb.IdentifyUI, tc libkb.TestContext, expectedFaves *favorites) {
152	uis := libkb.UIs{
153		IdentifyUI: idUI,
154	}
155	arg := keybase1.FavoriteAddArg{
156		Folder: keybase1.FolderHandle{Name: name, FolderType: folderType, Created: created},
157	}
158	eng := NewFavoriteAdd(tc.G, &arg)
159	m := NewMetaContextForTest(tc).WithUIs(uis)
160	err := RunEngine2(m, eng)
161	if err != nil {
162		tc.T.Fatal(err)
163	}
164	eng.Wait()
165	if expectedFaves != nil {
166		expectedFaves.Push(keybase1.Folder{Name: name, FolderType: folderType})
167	}
168}
169
170func rmfav(name string, folderType keybase1.FolderType, tc libkb.TestContext, expectedFaves *favorites) {
171	arg := keybase1.FavoriteIgnoreArg{
172		Folder: keybase1.FolderHandle{Name: name, FolderType: folderType},
173	}
174	eng := NewFavoriteIgnore(tc.G, &arg)
175	m := libkb.NewMetaContextForTest(tc)
176	err := RunEngine2(m, eng)
177	if err != nil {
178		tc.T.Fatal(err)
179	}
180	if expectedFaves != nil {
181		expectedFaves.Remove(keybase1.Folder{Name: name, FolderType: folderType})
182	}
183}
184
185func listfav(tc libkb.TestContext) *favorites {
186	eng := NewFavoriteList(tc.G)
187	m := libkb.NewMetaContextForTest(tc)
188	err := RunEngine2(m, eng)
189	if err != nil {
190		tc.T.Fatal(err)
191	}
192	return newFavoritesFromServer(eng.Result().FavoriteFolders)
193}
194
195type favorites struct {
196	m map[string]bool
197}
198
199func newFavorites(un string) *favorites {
200	ret := &favorites{
201		m: make(map[string]bool),
202	}
203	for _, f := range defaultFaves(un) {
204		ret.Push(f)
205	}
206	return ret
207}
208
209func newFavoritesFromServer(v []keybase1.Folder) *favorites {
210	ret := &favorites{
211		m: make(map[string]bool),
212	}
213	for _, f := range v {
214		ret.Push(f)
215	}
216	return ret
217}
218
219func (v *favorites) Push(f keybase1.Folder) {
220	k := makeKey(f)
221	if !v.m[k] {
222		v.m[k] = true
223	}
224}
225
226func (v *favorites) Remove(f keybase1.Folder) {
227	delete(v.m, makeKey(f))
228}
229
230func (v favorites) Equal(b favorites) bool {
231	for k := range v.m {
232		if !b.m[k] {
233			return false
234		}
235	}
236	for k := range b.m {
237		if !v.m[k] {
238			return false
239		}
240	}
241	return true
242}
243
244func makeKey(f keybase1.Folder) string {
245	return fmt.Sprintf("%s:%v", f.Name, f.FolderType)
246}
247
248func defaultFaves(un string) []keybase1.Folder {
249	return []keybase1.Folder{
250		{Name: un, FolderType: keybase1.FolderType_PRIVATE},
251		{Name: un, FolderType: keybase1.FolderType_PUBLIC},
252	}
253}
254
255func (v *favorites) String() string {
256	var s []string
257	for f := range v.m {
258		s = append(s, f)
259	}
260	sort.Strings(s)
261	return strings.Join(s, ";")
262}
263