blob: 84be46089498ce118357dab1f3baeec2a930688d [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.apkzlib.zip;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import com.android.apkzlib.utils.ApkZLibPair;
import com.android.apkzlib.utils.IOExceptionRunnable;
import com.google.common.collect.Lists;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.Mockito;
public class ZFileNotificationTest {
private static class KeepListener extends ZFileExtension {
public int open;
public int beforeUpdated;
public int updated;
public int closed;
public List<ApkZLibPair<StoredEntry, StoredEntry>> added;
public List<StoredEntry> removed;
public IOExceptionRunnable returnRunnable;
KeepListener() {
reset();
}
@Nullable
@Override
public IOExceptionRunnable open() {
open++;
return returnRunnable;
}
@Nullable
@Override
public IOExceptionRunnable beforeUpdate() {
beforeUpdated++;
return returnRunnable;
}
@Override
public void updated() {
updated++;
}
@Override
public void closed() {
closed++;
}
@Nullable
@Override
public IOExceptionRunnable added(@Nonnull StoredEntry entry,
@Nullable StoredEntry replaced) {
added.add(new ApkZLibPair<>(entry, replaced));
return returnRunnable;
}
@Nullable
@Override
public IOExceptionRunnable removed(@Nonnull StoredEntry entry) {
removed.add(entry);
return returnRunnable;
}
void reset() {
open = 0;
beforeUpdated = 0;
updated = 0;
closed = 0;
added = Lists.newArrayList();
removed = Lists.newArrayList();
}
void assertClear() {
assertEquals(0, open);
assertEquals(0, beforeUpdated);
assertEquals(0, updated);
assertEquals(0, closed);
assertEquals(0, added.size());
assertEquals(0, removed.size());
}
}
@Rule
public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
@Test
public void notifyAddFile() throws Exception {
try (ZFile zf = new ZFile(new File(mTemporaryFolder.getRoot(), "a.zip"))) {
KeepListener kl = new KeepListener();
zf.addZFileExtension(kl);
kl.assertClear();
zf.add("foo", new ByteArrayInputStream(new byte[] { 1, 2 }));
zf.finishAllBackgroundTasks();
assertEquals(1, kl.added.size());
StoredEntry addedSe = kl.added.get(0).v1;
assertNull(kl.added.get(0).v2);
kl.added.clear();
kl.assertClear();
StoredEntry foo = zf.get("foo");
assertNotNull(foo);
assertSame(foo, addedSe);
}
}
@Test
public void notifyRemoveFile() throws Exception {
try (ZFile zf = new ZFile(new File(mTemporaryFolder.getRoot(), "a.zip"))) {
KeepListener kl = new KeepListener();
zf.addZFileExtension(kl);
kl.assertClear();
zf.add("foo", new ByteArrayInputStream(new byte[] { 1, 2 }));
zf.finishAllBackgroundTasks();
kl.reset();
StoredEntry foo = zf.get("foo");
assertNotNull(foo);
foo.delete();
assertEquals(1, kl.removed.size());
assertSame(foo, kl.removed.get(0));
kl.removed.clear();
kl.assertClear();
}
}
@Test
public void notifyUpdateFile() throws Exception {
try (ZFile zf = new ZFile(new File(mTemporaryFolder.getRoot(), "a.zip"))) {
KeepListener kl = new KeepListener();
zf.addZFileExtension(kl);
kl.assertClear();
zf.add("foo", new ByteArrayInputStream(new byte[] { 1, 2 }));
zf.finishAllBackgroundTasks();
StoredEntry foo1 = zf.get("foo");
kl.reset();
zf.add("foo", new ByteArrayInputStream(new byte[] { 2, 3 }));
zf.finishAllBackgroundTasks();
StoredEntry foo2 = zf.get("foo");
assertEquals(1, kl.added.size());
assertSame(foo2, kl.added.get(0).v1);
assertSame(foo1, kl.added.get(0).v2);
kl.added.clear();
kl.assertClear();
}
}
@Test
public void notifyOpenUpdateClose() throws Exception {
KeepListener kl = new KeepListener();
try (ZFile zf = new ZFile(new File(mTemporaryFolder.getRoot(), "a.zip"))) {
zf.addZFileExtension(kl);
kl.assertClear();
zf.add("foo", new ByteArrayInputStream(new byte[] { 1, 2 }));
zf.finishAllBackgroundTasks();
kl.reset();
}
assertEquals(1, kl.open);
kl.open = 0;
assertEquals(1, kl.beforeUpdated);
assertEquals(1, kl.updated);
kl.beforeUpdated = 0;
kl.updated = 0;
assertEquals(1, kl.closed);
kl.closed = 0;
kl.assertClear();
}
@Test
public void notifyOpenUpdate() throws Exception {
KeepListener kl = new KeepListener();
try (ZFile zf = new ZFile(new File(mTemporaryFolder.getRoot(), "a.zip"))) {
zf.addZFileExtension(kl);
kl.assertClear();
zf.add("foo", new ByteArrayInputStream(new byte[] { 1, 2 }));
zf.finishAllBackgroundTasks();
kl.reset();
zf.update();
assertEquals(1, kl.open);
kl.open = 0;
assertEquals(1, kl.beforeUpdated);
assertEquals(1, kl.updated);
kl.beforeUpdated = 0;
kl.updated = 0;
kl.assertClear();
}
}
@Test
public void notifyUpdate() throws Exception {
try (ZFile zf = new ZFile(new File(mTemporaryFolder.getRoot(), "a.zip"))) {
KeepListener kl = new KeepListener();
zf.addZFileExtension(kl);
kl.assertClear();
zf.add("foo", new ByteArrayInputStream(new byte[] { 1, 2 }));
zf.update();
kl.reset();
zf.add("bar", new ByteArrayInputStream(new byte[] { 2, 3 }));
zf.finishAllBackgroundTasks();
kl.reset();
zf.update();
assertEquals(1, kl.beforeUpdated);
assertEquals(1, kl.updated);
kl.beforeUpdated = 0;
kl.updated = 0;
kl.assertClear();
}
}
@Test
public void removedListenersAreNotNotified() throws Exception {
try (ZFile zf = new ZFile(new File(mTemporaryFolder.getRoot(), "a.zip"))) {
KeepListener kl = new KeepListener();
zf.addZFileExtension(kl);
kl.assertClear();
zf.add("foo", new ByteArrayInputStream(new byte[] { 1, 2 }));
zf.finishAllBackgroundTasks();
assertEquals(1, kl.added.size());
kl.added.clear();
kl.assertClear();
zf.removeZFileExtension(kl);
zf.add("foo", new ByteArrayInputStream(new byte[] { 2, 3 }));
zf.finishAllBackgroundTasks();
kl.assertClear();
}
}
@Test
public void actionsExecutedAtEndOfNotification() throws Exception {
try (ZFile zf = new ZFile(new File(mTemporaryFolder.getRoot(), "a.zip"))) {
IOException death[] = new IOException[1];
KeepListener kl1 = new KeepListener();
zf.addZFileExtension(kl1);
kl1.returnRunnable = new IOExceptionRunnable() {
private boolean once = false;
@Override
public void run() {
if (once) {
return;
}
once = true;
try {
zf.add("foo", new ByteArrayInputStream(new byte[] { 1, 2 }));
} catch (IOException e) {
death[0] = e;
}
}
};
KeepListener kl2 = new KeepListener();
zf.addZFileExtension(kl2);
kl2.returnRunnable = new IOExceptionRunnable() {
private boolean once = false;
@Override
public void run() {
if (once) {
return;
}
once = true;
try {
zf.add("bar", new ByteArrayInputStream(new byte[] { 1, 2 }));
} catch (IOException e) {
death[0] = e;
}
}
};
kl1.assertClear();
kl2.assertClear();
zf.add("xpto", new ByteArrayInputStream(new byte[] { 1, 2 }));
zf.finishAllBackgroundTasks();
assertEquals(3, kl1.added.size());
kl1.added.clear();
kl1.assertClear();
assertEquals(3, kl2.added.size());
kl2.added.clear();
kl2.assertClear();
assertNull(death[0]);
}
}
@Test
public void canAddFilesDuringUpdateNotification() throws Exception {
File zipFile = new File(mTemporaryFolder.getRoot(), "a.zip");
try (ZFile zf = new ZFile(zipFile)) {
IOException death[] = new IOException[1];
KeepListener kl1 = new KeepListener();
zf.addZFileExtension(kl1);
zf.add("foo", new ByteArrayInputStream(new byte[] { 1, 2 }));
zf.finishAllBackgroundTasks();
kl1.returnRunnable = new IOExceptionRunnable() {
private boolean once = false;
@Override
public void run() {
if (once) {
return;
}
once = true;
try {
zf.add("bar", new ByteArrayInputStream(new byte[] { 1, 2 }));
} catch (IOException e) {
death[0] = e;
}
}
};
}
try (ZFile zf2 = new ZFile(zipFile)) {
StoredEntry fooFile = zf2.get("foo");
assertNotNull(fooFile);
StoredEntry barFile = zf2.get("bar");
assertNotNull(barFile);
}
}
@Test
public void notifyOnceEntriesWritten() throws Exception {
File zipFile = new File(mTemporaryFolder.getRoot(), "a.zip");
ZFileExtension ext = Mockito.mock(ZFileExtension.class);
try (ZFile zf = new ZFile(zipFile)) {
zf.addZFileExtension(ext);
zf.add("foo", new ByteArrayInputStream(new byte[] { 1, 2 }));
zf.finishAllBackgroundTasks();
Mockito.verify(ext, Mockito.times(0)).entriesWritten();
}
Mockito.verify(ext, Mockito.times(1)).entriesWritten();
}
@Test
public void notifyTwiceEntriesWrittenIfCdChanged() throws Exception {
File zipFile = new File(mTemporaryFolder.getRoot(), "a.zip");
ZFileExtension ext = Mockito.mock(ZFileExtension.class);
try (ZFile zf = new ZFile(zipFile)) {
Mockito.doAnswer((invocation) -> {
zf.setExtraDirectoryOffset(10);
Mockito.doNothing().when(ext).entriesWritten();
return null;
}).when(ext).entriesWritten();
zf.addZFileExtension(ext);
zf.add("foo", new ByteArrayInputStream(new byte[] { 1, 2 }));
zf.finishAllBackgroundTasks();
Mockito.verify(ext, Mockito.times(0)).entriesWritten();
}
Mockito.verify(ext, Mockito.times(2)).entriesWritten();
}
}