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