From 607feeb5ec4a5c6d75562456bdf0a10f8ad12ea8 Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Wed, 31 Jul 2019 06:53:40 +0200 Subject: [PATCH] =?utf8?q?=F0=9F=8E=A8=20Replace=20SoneInserterTest=20with?= =?utf8?q?=20Kotlin=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .../pterodactylus/sone/core/SoneInserterTest.java | 286 --------------------- .../pterodactylus/sone/core/SoneInserterTest.kt | 239 +++++++++++++++++ 2 files changed, 239 insertions(+), 286 deletions(-) delete mode 100644 src/test/java/net/pterodactylus/sone/core/SoneInserterTest.java create mode 100644 src/test/kotlin/net/pterodactylus/sone/core/SoneInserterTest.kt diff --git a/src/test/java/net/pterodactylus/sone/core/SoneInserterTest.java b/src/test/java/net/pterodactylus/sone/core/SoneInserterTest.java deleted file mode 100644 index f990500..0000000 --- a/src/test/java/net/pterodactylus/sone/core/SoneInserterTest.java +++ /dev/null @@ -1,286 +0,0 @@ -package net.pterodactylus.sone.core; - -import static com.google.common.io.ByteStreams.toByteArray; -import static com.google.common.util.concurrent.MoreExecutors.directExecutor; -import static java.lang.System.currentTimeMillis; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.nullValue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.hamcrest.MockitoHamcrest.argThat; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -import net.pterodactylus.sone.core.SoneInserter.ManifestCreator; -import net.pterodactylus.sone.core.event.InsertionDelayChangedEvent; -import net.pterodactylus.sone.core.event.SoneEvent; -import net.pterodactylus.sone.core.event.SoneInsertAbortedEvent; -import net.pterodactylus.sone.core.event.SoneInsertedEvent; -import net.pterodactylus.sone.core.event.SoneInsertingEvent; -import net.pterodactylus.sone.data.Album; -import net.pterodactylus.sone.data.Sone; -import net.pterodactylus.sone.main.SonePlugin; - -import freenet.keys.FreenetURI; -import freenet.support.api.ManifestElement; - -import com.google.common.base.Charsets; -import com.google.common.base.Optional; -import com.google.common.eventbus.AsyncEventBus; -import com.google.common.eventbus.EventBus; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -/** - * Unit test for {@link SoneInserter} and its subclasses. - */ -public class SoneInserterTest { - - private final Core core = mock(Core.class); - private final EventBus eventBus = mock(EventBus.class); - private final FreenetInterface freenetInterface = mock(FreenetInterface.class); - - @Before - public void setupCore() { - UpdateChecker updateChecker = mock(UpdateChecker.class); - when(core.getUpdateChecker()).thenReturn(updateChecker); - when(core.getSone(anyString())).thenReturn(null); - } - - @Test - public void insertionDelayIsForwardedToSoneInserter() { - EventBus eventBus = new AsyncEventBus(directExecutor()); - eventBus.register(new SoneInserter(core, eventBus, freenetInterface, "SoneId")); - eventBus.post(new InsertionDelayChangedEvent(15)); - assertThat(SoneInserter.getInsertionDelay().get(), is(15)); - } - - private Sone createSone(FreenetURI insertUri, String fingerprint) { - Sone sone = mock(Sone.class); - when(sone.getInsertUri()).thenReturn(insertUri); - when(sone.getFingerprint()).thenReturn(fingerprint); - when(sone.getRootAlbum()).thenReturn(mock(Album.class)); - when(core.getSone(anyString())).thenReturn(sone); - return sone; - } - - @Test - public void isModifiedIsTrueIfModificationDetectorSaysSo() { - SoneModificationDetector soneModificationDetector = mock(SoneModificationDetector.class); - when(soneModificationDetector.isModified()).thenReturn(true); - SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1); - assertThat(soneInserter.isModified(), is(true)); - } - - @Test - public void isModifiedIsFalseIfModificationDetectorSaysSo() { - SoneModificationDetector soneModificationDetector = mock(SoneModificationDetector.class); - SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1); - assertThat(soneInserter.isModified(), is(false)); - } - - @Test - public void lastFingerprintIsStoredCorrectly() { - SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId"); - soneInserter.setLastInsertFingerprint("last-fingerprint"); - assertThat(soneInserter.getLastInsertFingerprint(), is("last-fingerprint")); - } - - @Test - public void soneInserterStopsWhenItShould() { - SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId"); - soneInserter.stop(); - soneInserter.serviceRun(); - } - - @Test - public void soneInserterInsertsASoneIfItIsEligible() throws SoneException { - FreenetURI insertUri = mock(FreenetURI.class); - final FreenetURI finalUri = mock(FreenetURI.class); - String fingerprint = "fingerprint"; - Sone sone = createSone(insertUri, fingerprint); - SoneModificationDetector soneModificationDetector = mock(SoneModificationDetector.class); - when(soneModificationDetector.isEligibleForInsert()).thenReturn(true); - when(freenetInterface.insertDirectory(eq(insertUri), any(HashMap.class), eq("index.html"))).thenReturn(finalUri); - final SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1); - doAnswer(new Answer() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - soneInserter.stop(); - return null; - } - }).when(core).touchConfiguration(); - soneInserter.serviceRun(); - ArgumentCaptor soneEvents = ArgumentCaptor.forClass(SoneEvent.class); - verify(freenetInterface).insertDirectory(eq(insertUri), any(HashMap.class), eq("index.html")); - verify(eventBus, times(2)).post(soneEvents.capture()); - assertThat(soneEvents.getAllValues().get(0), instanceOf(SoneInsertingEvent.class)); - assertThat(soneEvents.getAllValues().get(0).getSone(), is(sone)); - assertThat(soneEvents.getAllValues().get(1), instanceOf(SoneInsertedEvent.class)); - assertThat(soneEvents.getAllValues().get(1).getSone(), is(sone)); - } - - @Test - public void soneInserterBailsOutIfItIsStoppedWhileInserting() throws SoneException { - FreenetURI insertUri = mock(FreenetURI.class); - final FreenetURI finalUri = mock(FreenetURI.class); - String fingerprint = "fingerprint"; - Sone sone = createSone(insertUri, fingerprint); - SoneModificationDetector soneModificationDetector = mock(SoneModificationDetector.class); - when(soneModificationDetector.isEligibleForInsert()).thenReturn(true); - final SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1); - when(freenetInterface.insertDirectory(eq(insertUri), any(HashMap.class), eq("index.html"))).thenAnswer(new Answer() { - @Override - public FreenetURI answer(InvocationOnMock invocation) throws Throwable { - soneInserter.stop(); - return finalUri; - } - }); - soneInserter.serviceRun(); - ArgumentCaptor soneEvents = ArgumentCaptor.forClass(SoneEvent.class); - verify(freenetInterface).insertDirectory(eq(insertUri), any(HashMap.class), eq("index.html")); - verify(eventBus, times(2)).post(soneEvents.capture()); - assertThat(soneEvents.getAllValues().get(0), instanceOf(SoneInsertingEvent.class)); - assertThat(soneEvents.getAllValues().get(0).getSone(), is(sone)); - assertThat(soneEvents.getAllValues().get(1), instanceOf(SoneInsertedEvent.class)); - assertThat(soneEvents.getAllValues().get(1).getSone(), is(sone)); - verify(core, never()).touchConfiguration(); - } - - @Test - public void soneInserterDoesNotInsertSoneIfItIsNotEligible() throws SoneException { - FreenetURI insertUri = mock(FreenetURI.class); - String fingerprint = "fingerprint"; - Sone sone = createSone(insertUri, fingerprint); - SoneModificationDetector soneModificationDetector = mock(SoneModificationDetector.class); - final SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1); - new Thread(new Runnable() { - @Override - public void run() { - try { - Thread.sleep(500); - } catch (InterruptedException ie1) { - throw new RuntimeException(ie1); - } - soneInserter.stop(); - } - }).start(); - soneInserter.serviceRun(); - verify(freenetInterface, never()).insertDirectory(eq(insertUri), any(HashMap.class), eq("index.html")); - verify(eventBus, never()).post(argThat(org.hamcrest.Matchers.any(SoneEvent.class))); - } - - @Test - public void soneInserterPostsAbortedEventIfAnExceptionOccurs() throws SoneException { - FreenetURI insertUri = mock(FreenetURI.class); - String fingerprint = "fingerprint"; - Sone sone = createSone(insertUri, fingerprint); - SoneModificationDetector soneModificationDetector = mock(SoneModificationDetector.class); - when(soneModificationDetector.isEligibleForInsert()).thenReturn(true); - final SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1); - final SoneException soneException = new SoneException(new Exception()); - when(freenetInterface.insertDirectory(eq(insertUri), any(HashMap.class), eq("index.html"))).thenAnswer(new Answer() { - @Override - public FreenetURI answer(InvocationOnMock invocation) throws Throwable { - soneInserter.stop(); - throw soneException; - } - }); - soneInserter.serviceRun(); - ArgumentCaptor soneEvents = ArgumentCaptor.forClass(SoneEvent.class); - verify(freenetInterface).insertDirectory(eq(insertUri), any(HashMap.class), eq("index.html")); - verify(eventBus, times(2)).post(soneEvents.capture()); - assertThat(soneEvents.getAllValues().get(0), instanceOf(SoneInsertingEvent.class)); - assertThat(soneEvents.getAllValues().get(0).getSone(), is(sone)); - assertThat(soneEvents.getAllValues().get(1), instanceOf(SoneInsertAbortedEvent.class)); - assertThat(soneEvents.getAllValues().get(1).getSone(), is(sone)); - verify(core, never()).touchConfiguration(); - } - - @Test - public void soneInserterExitsIfSoneIsUnknown() { - SoneModificationDetector soneModificationDetector = - mock(SoneModificationDetector.class); - SoneInserter soneInserter = - new SoneInserter(core, eventBus, freenetInterface, "SoneId", - soneModificationDetector, 1); - when(soneModificationDetector.isEligibleForInsert()).thenReturn(true); - when(core.getSone("SoneId")).thenReturn(null); - soneInserter.serviceRun(); - } - - @Test - public void soneInserterCatchesExceptionAndContinues() { - SoneModificationDetector soneModificationDetector = - mock(SoneModificationDetector.class); - final SoneInserter soneInserter = - new SoneInserter(core, eventBus, freenetInterface, "SoneId", - soneModificationDetector, 1); - Answer> stopInserterAndThrowException = - new Answer>() { - @Override - public Optional answer( - InvocationOnMock invocation) { - soneInserter.stop(); - throw new NullPointerException(); - } - }; - when(soneModificationDetector.isEligibleForInsert()).thenAnswer( - stopInserterAndThrowException); - soneInserter.serviceRun(); - } - - @Test - public void templateIsRenderedCorrectlyForManifestElement() - throws IOException { - Map soneProperties = new HashMap<>(); - soneProperties.put("id", "SoneId"); - ManifestCreator manifestCreator = new ManifestCreator(core, soneProperties); - long now = currentTimeMillis(); - when(core.getStartupTime()).thenReturn(now); - ManifestElement manifestElement = manifestCreator.createManifestElement("test.txt", "plain/text; charset=utf-8", "sone-inserter-manifest.txt"); - assertThat(manifestElement.getName(), is("test.txt")); - assertThat(manifestElement.getMimeTypeOverride(), is("plain/text; charset=utf-8")); - String templateContent = new String(toByteArray(manifestElement.getData().getInputStream()), Charsets.UTF_8); - assertThat(templateContent, containsString("Sone Version: " + SonePlugin.getPluginVersion() + "\n")); - assertThat(templateContent, containsString("Core Startup: " + now + "\n")); - assertThat(templateContent, containsString("Sone ID: " + "SoneId" + "\n")); - } - - @Test - public void invalidTemplateReturnsANullManifestElement() { - Map soneProperties = new HashMap<>(); - ManifestCreator manifestCreator = new ManifestCreator(core, soneProperties); - assertThat(manifestCreator.createManifestElement("test.txt", - "plain/text; charset=utf-8", - "sone-inserter-invalid-manifest.txt"), - nullValue()); - } - - @Test - public void errorWhileRenderingTemplateReturnsANullManifestElement() { - Map soneProperties = new HashMap<>(); - ManifestCreator manifestCreator = new ManifestCreator(core, soneProperties); - when(core.toString()).thenThrow(NullPointerException.class); - assertThat(manifestCreator.createManifestElement("test.txt", - "plain/text; charset=utf-8", - "sone-inserter-faulty-manifest.txt"), - nullValue()); - } - -} diff --git a/src/test/kotlin/net/pterodactylus/sone/core/SoneInserterTest.kt b/src/test/kotlin/net/pterodactylus/sone/core/SoneInserterTest.kt new file mode 100644 index 0000000..e541915 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/core/SoneInserterTest.kt @@ -0,0 +1,239 @@ +package net.pterodactylus.sone.core + +import com.google.common.base.* +import com.google.common.base.Optional +import com.google.common.eventbus.* +import com.google.common.io.ByteStreams.* +import com.google.common.util.concurrent.MoreExecutors.* +import freenet.keys.* +import net.pterodactylus.sone.core.SoneInserter.* +import net.pterodactylus.sone.core.event.* +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.test.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.* +import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyString +import org.mockito.ArgumentMatchers.eq +import org.mockito.Mockito.doAnswer +import org.mockito.Mockito.never +import org.mockito.Mockito.times +import org.mockito.Mockito.verify +import org.mockito.hamcrest.MockitoHamcrest.* +import org.mockito.stubbing.* +import java.lang.System.* +import java.util.* + +/** + * Unit test for [SoneInserter] and its subclasses. + */ +class SoneInserterTest { + + private val core = mock() + private val eventBus = mock() + private val freenetInterface = mock() + + @Before + fun setupCore() { + val updateChecker = mock() + whenever(core.updateChecker).thenReturn(updateChecker) + whenever(core.getSone(anyString())).thenReturn(null) + } + + @Test + fun `insertion delay is forwarded to sone inserter`() { + val eventBus = AsyncEventBus(directExecutor()) + eventBus.register(SoneInserter(core, eventBus, freenetInterface, "SoneId")) + eventBus.post(InsertionDelayChangedEvent(15)) + assertThat(SoneInserter.getInsertionDelay().get(), equalTo(15)) + } + + private fun createSone(insertUri: FreenetURI, fingerprint: String = "fingerprint"): Sone { + val sone = mock() + whenever(sone.insertUri).thenReturn(insertUri) + whenever(sone.fingerprint).thenReturn(fingerprint) + whenever(sone.rootAlbum).thenReturn(mock()) + whenever(core.getSone(anyString())).thenReturn(sone) + return sone + } + + @Test + fun `isModified is true if modification detector says so`() { + val soneModificationDetector = mock() + whenever(soneModificationDetector.isModified).thenReturn(true) + val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1) + assertThat(soneInserter.isModified, equalTo(true)) + } + + @Test + fun `isModified is false if modification detector says so`() { + val soneModificationDetector = mock() + val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1) + assertThat(soneInserter.isModified, equalTo(false)) + } + + @Test + fun `last fingerprint is stored correctly`() { + val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId") + soneInserter.lastInsertFingerprint = "last-fingerprint" + assertThat(soneInserter.lastInsertFingerprint, equalTo("last-fingerprint")) + } + + @Test + fun `sone inserter stops when it should`() { + val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId") + soneInserter.stop() + soneInserter.serviceRun() + } + + @Test + fun `sone inserter inserts a sone if it is eligible`() { + val insertUri = mock() + val finalUri = mock() + val sone = createSone(insertUri) + val soneModificationDetector = mock() + whenever(soneModificationDetector.isEligibleForInsert).thenReturn(true) + whenever(freenetInterface.insertDirectory(eq(insertUri), any>(), eq("index.html"))).thenReturn(finalUri) + val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1) + doAnswer { + soneInserter.stop() + null + }.`when`(core).touchConfiguration() + soneInserter.serviceRun() + val soneEvents = ArgumentCaptor.forClass(SoneEvent::class.java) + verify(freenetInterface).insertDirectory(eq(insertUri), any>(), eq("index.html")) + verify(eventBus, times(2)).post(soneEvents.capture()) + assertThat(soneEvents.allValues[0], instanceOf(SoneInsertingEvent::class.java)) + assertThat(soneEvents.allValues[0].sone, equalTo(sone)) + assertThat(soneEvents.allValues[1], instanceOf(SoneInsertedEvent::class.java)) + assertThat(soneEvents.allValues[1].sone, equalTo(sone)) + } + + @Test + fun `sone inserter bails out if it is stopped while inserting`() { + val insertUri = mock() + val finalUri = mock() + val sone = createSone(insertUri) + val soneModificationDetector = mock() + whenever(soneModificationDetector.isEligibleForInsert).thenReturn(true) + val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1) + whenever(freenetInterface.insertDirectory(eq(insertUri), any>(), eq("index.html"))).thenAnswer { + soneInserter.stop() + finalUri + } + soneInserter.serviceRun() + val soneEvents = ArgumentCaptor.forClass(SoneEvent::class.java) + verify(freenetInterface).insertDirectory(eq(insertUri), any>(), eq("index.html")) + verify(eventBus, times(2)).post(soneEvents.capture()) + assertThat(soneEvents.allValues[0], instanceOf(SoneInsertingEvent::class.java)) + assertThat(soneEvents.allValues[0].sone, equalTo(sone)) + assertThat(soneEvents.allValues[1], instanceOf(SoneInsertedEvent::class.java)) + assertThat(soneEvents.allValues[1].sone, equalTo(sone)) + verify(core, never()).touchConfiguration() + } + + @Test + fun `sone inserter does not insert sone if it is not eligible`() { + val insertUri = mock() + createSone(insertUri) + val soneModificationDetector = mock() + val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1) + Thread(Runnable { + try { + Thread.sleep(500) + } catch (ie1: InterruptedException) { + throw RuntimeException(ie1) + } + + soneInserter.stop() + }).start() + soneInserter.serviceRun() + verify(freenetInterface, never()).insertDirectory(eq(insertUri), any>(), eq("index.html")) + verify(eventBus, never()).post(argThat(org.hamcrest.Matchers.any(SoneEvent::class.java))) + } + + @Test + fun `sone inserter posts aborted event if an exception occurs`() { + val insertUri = mock() + val sone = createSone(insertUri) + val soneModificationDetector = mock() + whenever(soneModificationDetector.isEligibleForInsert).thenReturn(true) + val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1) + val soneException = SoneException(Exception()) + whenever(freenetInterface.insertDirectory(eq(insertUri), any>(), eq("index.html"))).thenAnswer { + soneInserter.stop() + throw soneException + } + soneInserter.serviceRun() + val soneEvents = ArgumentCaptor.forClass(SoneEvent::class.java) + verify(freenetInterface).insertDirectory(eq(insertUri), any>(), eq("index.html")) + verify(eventBus, times(2)).post(soneEvents.capture()) + assertThat(soneEvents.allValues[0], instanceOf(SoneInsertingEvent::class.java)) + assertThat(soneEvents.allValues[0].sone, equalTo(sone)) + assertThat(soneEvents.allValues[1], instanceOf(SoneInsertAbortedEvent::class.java)) + assertThat(soneEvents.allValues[1].sone, equalTo(sone)) + verify(core, never()).touchConfiguration() + } + + @Test + fun `sone inserter exits if sone is unknown`() { + val soneModificationDetector = mock() + val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1) + whenever(soneModificationDetector.isEligibleForInsert).thenReturn(true) + whenever(core.getSone("SoneId")).thenReturn(null) + soneInserter.serviceRun() + } + + @Test + fun `sone inserter catches exception and continues`() { + val soneModificationDetector = mock() + val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1) + val stopInserterAndThrowException = Answer> { + soneInserter.stop() + throw NullPointerException() + } + whenever(soneModificationDetector.isEligibleForInsert).thenAnswer(stopInserterAndThrowException) + soneInserter.serviceRun() + } + + @Test + fun `template is rendered correctly for manifest element`() { + val soneProperties = HashMap() + soneProperties["id"] = "SoneId" + val manifestCreator = ManifestCreator(core, soneProperties) + val now = currentTimeMillis() + whenever(core.startupTime).thenReturn(now) + val manifestElement = manifestCreator.createManifestElement("test.txt", "plain/text; charset=utf-8", "sone-inserter-manifest.txt") + assertThat(manifestElement!!.name, equalTo("test.txt")) + assertThat(manifestElement.mimeTypeOverride, equalTo("plain/text; charset=utf-8")) + val templateContent = String(toByteArray(manifestElement.data.inputStream), Charsets.UTF_8) + assertThat(templateContent, containsString("Sone Version: ${SonePlugin.getPluginVersion()}\n")) + assertThat(templateContent, containsString("Core Startup: $now\n")) + assertThat(templateContent, containsString("Sone ID: SoneId\n")) + } + + @Test + fun `invalid template returns anull manifest element`() { + val soneProperties = HashMap() + val manifestCreator = ManifestCreator(core, soneProperties) + assertThat(manifestCreator.createManifestElement("test.txt", + "plain/text; charset=utf-8", + "sone-inserter-invalid-manifest.txt"), + nullValue()) + } + + @Test + fun `error while rendering template returns a null manifest element`() { + val soneProperties = HashMap() + val manifestCreator = ManifestCreator(core, soneProperties) + whenever(core.toString()).thenThrow(NullPointerException::class.java) + assertThat(manifestCreator.createManifestElement("test.txt", + "plain/text; charset=utf-8", + "sone-inserter-faulty-manifest.txt"), + nullValue()) + } + +} -- 2.7.4