• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 Google LLC
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 package com.google.android.libraries.mobiledatadownload.file;
17 
18 import static com.google.android.libraries.mobiledatadownload.file.common.testing.StreamUtils.makeArrayOfBytesContent;
19 import static com.google.common.truth.Truth.assertThat;
20 import static org.mockito.ArgumentMatchers.any;
21 import static org.mockito.Mockito.doThrow;
22 import static org.mockito.Mockito.mock;
23 import static org.mockito.Mockito.times;
24 import static org.mockito.Mockito.verify;
25 import static org.mockito.Mockito.when;
26 
27 import android.net.Uri;
28 import com.google.android.libraries.mobiledatadownload.file.common.testing.BufferingMonitor;
29 import com.google.android.libraries.mobiledatadownload.file.spi.Monitor;
30 import com.google.thirdparty.robolectric.GoogleRobolectricTestRunner;
31 import java.io.ByteArrayOutputStream;
32 import java.io.IOException;
33 import java.io.OutputStream;
34 import java.util.Arrays;
35 import org.junit.Test;
36 import org.junit.runner.RunWith;
37 
38 /** Test {@link com.google.android.libraries.mobiledatadownload.file.MonitorOutputStream}. */
39 @RunWith(GoogleRobolectricTestRunner.class)
40 public class MonitorOutputStreamTest {
41 
42   private static final byte[] TEST_CONTENT = makeArrayOfBytesContent();
43 
44   @Test
monitorWrite_shouldSeeAllBytes()45   public void monitorWrite_shouldSeeAllBytes() throws Exception {
46     BufferingMonitor buffer = new BufferingMonitor();
47     Uri uri = Uri.parse("foo:");
48     OutputStream out = new ByteArrayOutputStream();
49     MonitorOutputStream stream =
50         MonitorOutputStream.newInstanceForWrite(Arrays.asList(buffer), uri, out);
51 
52     byte[] content0 = Arrays.copyOf(TEST_CONTENT, 7);
53     byte[] content1 = Arrays.copyOfRange(TEST_CONTENT, 7, 10);
54     stream.write(content0[0]);
55     stream.write(content0, 1, 6);
56     stream.write(content1);
57 
58     assertThat(buffer.bytesWritten()).isEqualTo(Arrays.copyOf(TEST_CONTENT, 10));
59   }
60 
61   @Test
monitorAppend_shouldSeeAllBytes()62   public void monitorAppend_shouldSeeAllBytes() throws Exception {
63     BufferingMonitor buffer = new BufferingMonitor();
64     Uri uri = Uri.parse("foo:");
65     OutputStream out = new ByteArrayOutputStream();
66     MonitorOutputStream stream =
67         MonitorOutputStream.newInstanceForAppend(Arrays.asList(buffer), uri, out);
68 
69     byte[] content0 = Arrays.copyOf(TEST_CONTENT, 7);
70     byte[] content1 = Arrays.copyOfRange(TEST_CONTENT, 7, 10);
71     stream.write(content0[0]);
72     stream.write(content0, 1, 6);
73     stream.write(content1);
74 
75     assertThat(buffer.bytesAppended()).isEqualTo(Arrays.copyOf(TEST_CONTENT, 10));
76   }
77 
78   @Test
monitorWrite_withNullOutputMonitor_shouldReturnNull()79   public void monitorWrite_withNullOutputMonitor_shouldReturnNull() throws Exception {
80     Monitor mockMonitor = mock(Monitor.class);
81     when(mockMonitor.monitorWrite(any())).thenReturn(null);
82     Uri uri = Uri.parse("foo:");
83     OutputStream out = new ByteArrayOutputStream();
84 
85     assertThat(MonitorOutputStream.newInstanceForWrite(Arrays.asList(mockMonitor), uri, out))
86         .isNull();
87   }
88 
89   @Test
monitorAppend_withNullOutputMonitor_shouldReturnNull()90   public void monitorAppend_withNullOutputMonitor_shouldReturnNull() throws Exception {
91     Monitor mockMonitor = mock(Monitor.class);
92     when(mockMonitor.monitorAppend(any())).thenReturn(null);
93     Uri uri = Uri.parse("foo:");
94     OutputStream out = new ByteArrayOutputStream();
95 
96     assertThat(MonitorOutputStream.newInstanceForAppend(Arrays.asList(mockMonitor), uri, out))
97         .isNull();
98   }
99 
100   @Test
monitorWrite_shouldCallClose()101   public void monitorWrite_shouldCallClose() throws Exception {
102     Monitor mockMonitor = mock(Monitor.class);
103     Monitor.OutputMonitor mockOutputMonitor = mock(Monitor.OutputMonitor.class);
104     when(mockMonitor.monitorWrite(any())).thenReturn(mockOutputMonitor);
105     Uri uri = Uri.parse("foo:");
106     FakeOutputStream fakeOut = new FakeOutputStream();
107     try (MonitorOutputStream stream =
108         MonitorOutputStream.newInstanceForWrite(Arrays.asList(mockMonitor), uri, fakeOut)) {
109       stream.write(TEST_CONTENT);
110     }
111     verify(mockOutputMonitor, times(1)).close();
112     assertThat(fakeOut.bytesWritten).isEqualTo(TEST_CONTENT.length);
113     assertThat(fakeOut.closed).isTrue();
114   }
115 
116   @Test
monitorWriteWithMonitorCloseException_shouldCallClose()117   public void monitorWriteWithMonitorCloseException_shouldCallClose() throws Exception {
118     Monitor mockMonitor = mock(Monitor.class);
119     Monitor.OutputMonitor mockOutputMonitor = mock(Monitor.OutputMonitor.class);
120     when(mockMonitor.monitorWrite(any())).thenReturn(mockOutputMonitor);
121     doThrow(new RuntimeException("Unchecked")).when(mockOutputMonitor).close();
122     Uri uri = Uri.parse("foo:");
123     FakeOutputStream fakeOut = new FakeOutputStream();
124     try (MonitorOutputStream stream =
125         MonitorOutputStream.newInstanceForWrite(Arrays.asList(mockMonitor), uri, fakeOut)) {
126       stream.write(TEST_CONTENT);
127     }
128     verify(mockOutputMonitor, times(1)).close();
129     assertThat(fakeOut.bytesWritten).isEqualTo(TEST_CONTENT.length);
130     assertThat(fakeOut.closed).isTrue();
131   }
132 
133   private static class FakeOutputStream extends OutputStream {
134     private boolean closed = true;
135     private int bytesWritten = 0;
136 
137     @Override
write(int b)138     public void write(int b) throws IOException {
139       bytesWritten += 1;
140     }
141 
142     @Override
close()143     public void close() throws IOException {
144       closed = true;
145     }
146   }
147 }
148