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.common.testing; 17 18 import android.net.Uri; 19 import com.google.android.libraries.mobiledatadownload.file.common.Fragment; 20 import com.google.android.libraries.mobiledatadownload.file.common.internal.ForwardingOutputStream; 21 import com.google.android.libraries.mobiledatadownload.file.spi.Transform; 22 import java.io.IOException; 23 import java.io.InputStream; 24 import java.io.OutputStream; 25 26 /** A Transform that throws IOException after writing N bytes of data (reads are unaffected). */ 27 public class WritesThrowTransform implements Transform { 28 29 private static final String NAME = "writethrows"; 30 private static final String LENGTH_SUBPARAM = "write_length"; 31 32 @Override name()33 public String name() { 34 return NAME; 35 } 36 37 @Override wrapForRead(Uri uri, InputStream wrapped)38 public InputStream wrapForRead(Uri uri, InputStream wrapped) throws IOException { 39 return wrapped; 40 } 41 42 @Override wrapForWrite(Uri uri, OutputStream wrapped)43 public OutputStream wrapForWrite(Uri uri, OutputStream wrapped) throws IOException { 44 return new ForwardingOutputStream(wrapped) { 45 long byteCount = getLengthSubparam(uri); 46 47 @Override 48 public void write(byte[] b) throws IOException { 49 write(b, 0, b.length); 50 } 51 52 @Override 53 public void write(byte[] b, int off, int len) throws IOException { 54 len = (int) Math.min(len, byteCount); // Write no more than byteCount bytes 55 out.write(b, off, len); 56 byteCount -= len; 57 if (byteCount == 0) { 58 throw new IOException("throwing"); 59 } 60 } 61 62 @Override 63 public void write(int b) throws IOException { 64 write(new byte[] {(byte) b}, 0, 1); 65 } 66 }; 67 } 68 69 @Override wrapForAppend(Uri uri, OutputStream wrapped)70 public OutputStream wrapForAppend(Uri uri, OutputStream wrapped) throws IOException { 71 return wrapForWrite(uri, wrapped); 72 } 73 74 /** Returns the value of {@link #LENGTH_SUBPARAM} in {@code param}, or 0 if not present. */ getLengthSubparam(Uri uri)75 private static long getLengthSubparam(Uri uri) { 76 String value = Fragment.getTransformSubParam(uri, NAME, LENGTH_SUBPARAM); 77 return value != null ? Long.parseLong(value) : 0; 78 } 79 } 80