1 /*
2  * Copyright (C) 2017 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.apksig.util;
18 
19 import static org.junit.Assert.assertEquals;
20 
21 import java.io.Closeable;
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.RandomAccessFile;
25 import java.nio.charset.StandardCharsets;
26 import java.nio.file.Files;
27 import org.junit.Test;
28 import org.junit.runner.RunWith;
29 import org.junit.runners.Parameterized;
30 
31 /**
32  * Tests for the {@link DataSource} returned by
33  * {@link DataSources#asDataSource(java.io.RandomAccessFile)}.
34  */
35 @RunWith(Parameterized.class)
36 public class DataSourceFromRAFTest extends DataSourceTestBase {
37 
38     @Parameterized.Parameters(name = "{0}")
data()39     public static DataSourceFromRAFFactory[] data() {
40         return DataSourceFromRAFFactory.values();
41     }
42 
43     @Parameterized.Parameter
44     public DataSourceFromRAFFactory factory;
45 
46     @Test
testFileSizeChangesVisible()47     public void testFileSizeChangesVisible() throws Exception {
48         try (CloseableWithDataSource c = createDataSource("abcdefg")) {
49             DataSource ds = c.getDataSource();
50             DataSource slice = ds.slice(3, 2);
51             File f = ((TmpFileCloseable) c.getCloseable()).getFile();
52             assertGetByteBufferEquals("abcdefg", ds, 0, (int) ds.size());
53             assertGetByteBufferEquals("de", slice, 0, (int) slice.size());
54             assertFeedEquals("cdefg", ds, 2, 5);
55             assertFeedEquals("e", slice, 1, 1);
56             assertCopyToEquals("cdefg", ds, 2, 5);
57             assertCopyToEquals("e", slice, 1, 1);
58             assertSliceEquals("cdefg", ds, 2, 5);
59             assertSliceEquals("e", slice, 1, 1);
60             try (RandomAccessFile raf = new RandomAccessFile(f, "rw")) {
61                 raf.seek(7);
62                 raf.write("hijkl".getBytes(StandardCharsets.UTF_8));
63             }
64 
65             assertEquals(12, ds.size());
66             assertGetByteBufferEquals("abcdefghijkl", ds, 0, (int) ds.size());
67             assertGetByteBufferEquals("de", slice, 0, (int) slice.size());
68             assertFeedEquals("cdefg", ds, 2, 5);
69             assertFeedEquals("fgh", ds, 5, 3);
70             assertCopyToEquals("fgh", ds, 5, 3);
71             assertSliceEquals("fgh", ds, 5, 3);
72         }
73     }
74 
75     @Override
createDataSource(byte[] contents)76     protected CloseableWithDataSource createDataSource(byte[] contents) throws IOException {
77         File tmp = File.createTempFile(DataSourceFromRAFTest.class.getSimpleName(), ".bin");
78         RandomAccessFile f = null;
79         try {
80             Files.write(tmp.toPath(), contents);
81             f = new RandomAccessFile(tmp, "r");
82         } finally {
83             if (f == null) {
84                 tmp.delete();
85             }
86         }
87 
88         return CloseableWithDataSource.of(
89                 factory.create(f),
90                 new TmpFileCloseable(tmp, f));
91     }
92 
93     /**
94      * {@link Closeable} which closes the delegate {@code Closeable} and deletes the provided file.
95      */
96     static class TmpFileCloseable implements Closeable {
97         private final File mFile;
98         private final Closeable mDelegate;
99 
TmpFileCloseable(File file, Closeable closeable)100         TmpFileCloseable(File file, Closeable closeable) {
101             mFile = file;
102             mDelegate = closeable;
103         }
104 
getFile()105         File getFile() {
106             return mFile;
107         }
108 
109         @Override
close()110         public void close() throws IOException {
111             try {
112                 if (mDelegate != null) {
113                     mDelegate.close();
114                 }
115             } finally {
116                 if (mFile != null) {
117                     mFile.delete();
118                 }
119             }
120         }
121     }
122 }
123