1 /*
2  * Copyright (C) 2019 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.archives;
18 
19 import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
20 
21 import android.os.ParcelFileDescriptor;
22 import android.util.Log;
23 
24 import androidx.test.platform.app.InstrumentationRegistry;
25 
26 import org.apache.commons.compress.utils.IOUtils;
27 import org.junit.rules.TestName;
28 import org.junit.runner.Description;
29 
30 import java.io.FileInputStream;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.io.InputStreamReader;
34 import java.nio.file.Files;
35 import java.nio.file.Path;
36 import java.nio.file.StandardCopyOption;
37 import java.nio.file.attribute.FileAttribute;
38 import java.nio.file.attribute.PosixFilePermission;
39 import java.nio.file.attribute.PosixFilePermissions;
40 import java.util.ArrayList;
41 import java.util.List;
42 import java.util.Locale;
43 import java.util.Set;
44 
45 public class ArchiveFileTestRule extends TestName {
46     private static final String TAG = ArchiveFileTestRule.class.getSimpleName();
47 
48     private final List<Path> mTemporaries;
49     private final List<ParcelFileDescriptor> mParcelFileDescriptors;
50 
51     private String mClassName;
52     private String mMethodName;
53     private Path mTemporaryPath;
54 
ArchiveFileTestRule()55     public ArchiveFileTestRule() {
56         mTemporaries = new ArrayList<>();
57         mParcelFileDescriptors = new ArrayList<>();
58     }
59 
60     @Override
starting(Description description)61     protected void starting(Description description) {
62         super.starting(description);
63         mClassName = description.getClassName();
64         mMethodName = description.getMethodName();
65 
66         try {
67             mTemporaryPath = Files.createTempDirectory(
68                     InstrumentationRegistry.getInstrumentation()
69                             .getTargetContext().getCacheDir().toPath(),
70                     mClassName);
71         } catch (IOException e) {
72             Log.e(TAG, String.format(Locale.ENGLISH,
73                     "It can't create temporary directory in the staring of %s.%s.",
74                     mClassName, mMethodName));
75         }
76     }
77 
78     @Override
finished(Description description)79     protected void finished(Description description) {
80         super.finished(description);
81 
82         for (Path path : mTemporaries) {
83             if (path != null) {
84                 path.toFile().delete();
85             }
86         }
87 
88         mTemporaryPath.toFile().delete();
89 
90         for (ParcelFileDescriptor parcelFileDescriptor : mParcelFileDescriptors) {
91             IOUtils.closeQuietly(parcelFileDescriptor);
92         }
93     }
94 
95     /**
96      * To generate the temporary file and return the file path.
97      *
98      * @param suffix the suffix of the temporary file name
99      * @return the file path
100      * @throws IOException to create temporary file fail raises IOException
101      */
generateFile(String suffix)102     public Path generateFile(String suffix) throws IOException {
103         Set<PosixFilePermission> perm = PosixFilePermissions.fromString("rwx------");
104         FileAttribute<Set<PosixFilePermission>> attr = PosixFilePermissions.asFileAttribute(perm);
105         Path filePath = Files.createTempFile(mTemporaryPath, mMethodName, suffix, attr);
106         mTemporaries.add(filePath);
107         return filePath;
108     }
109 
110     /**
111      * To dump asset path file as temporary file. There are some problems to get the file
112      * descriptor from the asset files in instrumentation context. It's null pointer. It needs to
113      * dump to temporary file in the target context of the instrumentation.
114      *
115      * @param assetPath assetPath in test context
116      * @param suffix the suffix of the temporary file name
117      * @return the file path
118      */
dumpAssetFile(String assetPath, String suffix)119     public Path dumpAssetFile(String assetPath, String suffix) throws IOException {
120         Path destinationPath = generateFile(suffix);
121 
122         try (InputStream inputStream = InstrumentationRegistry.getInstrumentation()
123                 .getContext().getAssets().open(assetPath)) {
124             Files.copy(inputStream, destinationPath, StandardCopyOption.REPLACE_EXISTING);
125         }
126 
127         return destinationPath;
128     }
129 
130     /**
131      * To dump asset path file as temporary file. There are some problems to get the file
132      * descriptor from the asset files in instrumentation context. It's null pointer. It needs to
133      * dump to temporary file in the target context of the instrumentation.
134      *
135      * @param assetPath assetPath in test context
136      * @param suffix the suffix of the temporary file name
137      * @return the file path
138      */
openAssetFile(String assetPath, String suffix)139     public ParcelFileDescriptor openAssetFile(String assetPath, String suffix) throws IOException {
140         Path destinationPath = dumpAssetFile(assetPath, suffix);
141 
142         ParcelFileDescriptor parcelFileDescriptor = ParcelFileDescriptor
143                 .open(destinationPath.toFile(), MODE_READ_ONLY);
144 
145         mParcelFileDescriptors.add(parcelFileDescriptor);
146         return parcelFileDescriptor;
147     }
148 
149     /**
150      * To get asset content that is a type of text.
151      *
152      * @param assetPath assetPath in test context
153      * @return the text content
154      */
getAssetText(String assetPath)155     public String getAssetText(String assetPath) throws IOException {
156         ParcelFileDescriptor parcelFileDescriptor = openAssetFile(assetPath, ".text");
157 
158         try (FileInputStream fileInputStream =
159                 new FileInputStream(parcelFileDescriptor.getFileDescriptor())) {
160             return getStringFromInputStream(fileInputStream);
161         }
162     }
163 
getStringFromInputStream(InputStream inputStream)164     public static String getStringFromInputStream(InputStream inputStream) throws IOException {
165         InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
166 
167         int size = inputStream.available();
168         char[] buffer = new char[size];
169 
170         inputStreamReader.read(buffer);
171 
172         return new String(buffer);
173     }
174 }
175