1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.documentsui.roots;
18 
19 import static com.google.common.collect.Lists.newArrayList;
20 import static com.google.common.truth.Truth.assertThat;
21 
22 import android.provider.DocumentsContract;
23 import android.test.AndroidTestCase;
24 
25 import androidx.annotation.Nullable;
26 import androidx.test.filters.SmallTest;
27 
28 import com.android.documentsui.base.Providers;
29 import com.android.documentsui.base.RootInfo;
30 import com.android.documentsui.base.State;
31 import com.android.documentsui.base.UserId;
32 
33 import com.google.common.collect.Lists;
34 import com.google.common.truth.Correspondence;
35 
36 import java.util.Arrays;
37 import java.util.List;
38 import java.util.Objects;
39 
40 @SmallTest
41 public class ProvidersAccessTest extends AndroidTestCase {
42 
43     private static final UserId OTHER_USER = UserId.of(UserId.DEFAULT_USER.getIdentifier() + 1);
44     private static final Correspondence<RootInfo, RootInfo> USER_ID_MIME_TYPES_CORRESPONDENCE =
45             Correspondence.from((@Nullable RootInfo actual, @Nullable RootInfo expected) -> {
46                     return actual != null && expected != null
47                             && Objects.equals(actual.userId, expected.userId)
48                             && Arrays.equals(actual.derivedMimeTypes, expected.derivedMimeTypes);
49             }, "has same userId and mimeTypes as in");
50 
51     private static RootInfo mNull = buildForMimeTypes((String[]) null);
52     private static RootInfo mEmpty = buildForMimeTypes();
53     private static RootInfo mWild = buildForMimeTypes("*/*");
54     private static RootInfo mImages = buildForMimeTypes("image/*");
55     private static RootInfo mAudio = buildForMimeTypes(
56             "audio/*", "application/ogg", "application/x-flac");
57     private static RootInfo mDocs = buildForMimeTypes(
58             "application/msword", "application/vnd.ms-excel");
59     private static RootInfo mMalformed1 = buildForMimeTypes("meow");
60     private static RootInfo mMalformed2 = buildForMimeTypes("*/meow");
61     private static RootInfo mImagesOtherUser = buildForMimeTypes(OTHER_USER, "image/*");
62 
63     private List<RootInfo> mRoots;
64 
65     private State mState;
66 
67     @Override
setUp()68     protected void setUp() throws Exception {
69         super.setUp();
70 
71         mRoots = Lists.newArrayList(
72                 mNull, mWild, mEmpty, mImages, mAudio, mDocs, mMalformed1, mMalformed2,
73                 mImagesOtherUser);
74 
75         mState = new State();
76         mState.action = State.ACTION_OPEN;
77         mState.localOnly = false;
78     }
79 
testMatchingRoots_Everything()80     public void testMatchingRoots_Everything() throws Exception {
81         mState.acceptMimes = new String[]{"*/*"};
82         assertContainsExactly(
83                 newArrayList(mNull, mWild, mImages, mAudio, mDocs, mMalformed1, mMalformed2),
84                 ProvidersAccess.getMatchingRoots(mRoots, mState));
85     }
86 
testMatchingRoots_PngOrWild()87     public void testMatchingRoots_PngOrWild() throws Exception {
88         mState.acceptMimes = new String[] { "image/png", "*/*" };
89         assertContainsExactly(
90                 newArrayList(mNull, mWild, mImages, mAudio, mDocs, mMalformed1, mMalformed2),
91                 ProvidersAccess.getMatchingRoots(mRoots, mState));
92     }
93 
testMatchingRoots_AudioWild()94     public void testMatchingRoots_AudioWild() throws Exception {
95         mState.acceptMimes = new String[] { "audio/*" };
96         assertContainsExactly(
97                 newArrayList(mNull, mWild, mAudio),
98                 ProvidersAccess.getMatchingRoots(mRoots, mState));
99     }
100 
testMatchingRoots_AudioWildOrImageWild()101     public void testMatchingRoots_AudioWildOrImageWild() throws Exception {
102         mState.acceptMimes = new String[] { "audio/*", "image/*" };
103         assertContainsExactly(
104                 newArrayList(mNull, mWild, mAudio, mImages),
105                 ProvidersAccess.getMatchingRoots(mRoots, mState));
106     }
107 
testMatchingRoots_AudioSpecific()108     public void testMatchingRoots_AudioSpecific() throws Exception {
109         mState.acceptMimes = new String[] { "audio/mpeg" };
110         assertContainsExactly(
111                 newArrayList(mNull, mWild, mAudio),
112                 ProvidersAccess.getMatchingRoots(mRoots, mState));
113     }
114 
testMatchingRoots_Document()115     public void testMatchingRoots_Document() throws Exception {
116         mState.acceptMimes = new String[] { "application/msword" };
117         assertContainsExactly(
118                 newArrayList(mNull, mWild, mDocs),
119                 ProvidersAccess.getMatchingRoots(mRoots, mState));
120     }
121 
testMatchingRoots_Application()122     public void testMatchingRoots_Application() throws Exception {
123         mState.acceptMimes = new String[] { "application/*" };
124         assertContainsExactly(
125                 newArrayList(mNull, mWild, mAudio, mDocs),
126                 ProvidersAccess.getMatchingRoots(mRoots, mState));
127     }
128 
testMatchingRoots_FlacOrPng()129     public void testMatchingRoots_FlacOrPng() throws Exception {
130         mState.acceptMimes = new String[] { "application/x-flac", "image/png" };
131         assertContainsExactly(
132                 newArrayList(mNull, mWild, mAudio, mImages),
133                 ProvidersAccess.getMatchingRoots(mRoots, mState));
134     }
135 
testMatchingRoots_FlacOrPng_crossProfile()136     public void testMatchingRoots_FlacOrPng_crossProfile() throws Exception {
137         mState.supportsCrossProfile = true;
138         mState.acceptMimes = new String[]{"application/x-flac", "image/png"};
139         assertContainsExactly(
140                 newArrayList(mNull, mWild, mAudio, mImages, mImagesOtherUser),
141                 ProvidersAccess.getMatchingRoots(mRoots, mState));
142     }
143 
testDefaultRoot()144     public void testDefaultRoot() {
145         mState.acceptMimes = new String[] { "*/*" };
146         assertNull(ProvidersAccess.getDefaultRoot(mRoots, mState));
147 
148         RootInfo downloads = buildForMimeTypes("*/*");
149         downloads.authority = Providers.AUTHORITY_DOWNLOADS;
150         mRoots.add(downloads);
151 
152         assertEquals(downloads, ProvidersAccess.getDefaultRoot(mRoots, mState));
153     }
154 
testDefaultRoot_openDocumentTree()155     public void testDefaultRoot_openDocumentTree() {
156         RootInfo storage = buildForMimeTypes("*/*");
157         storage.authority = Providers.AUTHORITY_STORAGE;
158         storage.flags = DocumentsContract.Root.FLAG_SUPPORTS_IS_CHILD;
159         mRoots.add(storage);
160 
161         mState.action = State.ACTION_OPEN_TREE;
162         mState.acceptMimes = new String[] { "*/*" };
163         assertEquals(storage, ProvidersAccess.getDefaultRoot(mRoots, mState));
164     }
165 
testExcludedAuthorities()166     public void testExcludedAuthorities() throws Exception {
167         final List<RootInfo> roots = newArrayList();
168 
169         // Set up some roots
170         for (int i = 0; i < 5; ++i) {
171             RootInfo root = new RootInfo();
172             root.userId = UserId.DEFAULT_USER;
173             root.authority = "authority" + i;
174             roots.add(root);
175         }
176         // Make some allowed authorities
177         List<RootInfo> allowedRoots = newArrayList(
178             roots.get(0), roots.get(2), roots.get(4));
179         // Set up the excluded authority list
180         for (RootInfo root: roots) {
181             if (!allowedRoots.contains(root)) {
182                 mState.excludedAuthorities.add(root.authority);
183             }
184         }
185         mState.acceptMimes = new String[] { "*/*" };
186 
187         assertContainsExactly(
188             allowedRoots,
189             ProvidersAccess.getMatchingRoots(roots, mState));
190     }
191 
assertContainsExactly(List<RootInfo> expected, List<RootInfo> actual)192     private static void assertContainsExactly(List<RootInfo> expected, List<RootInfo> actual) {
193         assertThat(actual)
194                 .comparingElementsUsing(USER_ID_MIME_TYPES_CORRESPONDENCE)
195                 .containsExactlyElementsIn(expected);
196     }
197 
buildForMimeTypes(String... mimeTypes)198     private static RootInfo buildForMimeTypes(String... mimeTypes) {
199         return buildForMimeTypes(UserId.DEFAULT_USER, mimeTypes);
200     }
201 
buildForMimeTypes(UserId userId, String... mimeTypes)202     private static RootInfo buildForMimeTypes(UserId userId, String... mimeTypes) {
203         final RootInfo root = new RootInfo();
204         root.userId = userId;
205         root.derivedMimeTypes = mimeTypes;
206         return root;
207     }
208 }
209