GEODE-2648: always move deleted files to dirOfDeletedFiles
Project: http://git-wip-us.apache.org/repos/asf/geode/repo Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/1f276d31 Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/1f276d31 Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/1f276d31 Branch: refs/heads/feature/GEODE-2420 Commit: 1f276d312db2c3ca0505ec0664c2c3d47286b47d Parents: cfb039c Author: Kirk Lund <[email protected]> Authored: Mon Mar 13 16:02:53 2017 -0700 Committer: Ken Howe <[email protected]> Committed: Mon Mar 27 14:00:40 2017 -0700 ---------------------------------------------------------------------- .../apache/geode/internal/util/ArrayUtils.java | 27 +++ .../DiskSpaceLimitIntegrationTest.java | 50 +++-- .../internal/util/ArrayUtilsJUnitTest.java | 176 --------------- .../geode/internal/util/ArrayUtilsTest.java | 219 +++++++++++++++++++ 4 files changed, 274 insertions(+), 198 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/geode/blob/1f276d31/geode-core/src/main/java/org/apache/geode/internal/util/ArrayUtils.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/util/ArrayUtils.java b/geode-core/src/main/java/org/apache/geode/internal/util/ArrayUtils.java index 3459e16..6f1c7cc 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/util/ArrayUtils.java +++ b/geode-core/src/main/java/org/apache/geode/internal/util/ArrayUtils.java @@ -15,7 +15,12 @@ package org.apache.geode.internal.util; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.RandomAccess; import org.apache.geode.internal.lang.StringUtils; import org.apache.geode.internal.offheap.annotations.Unretained; @@ -361,4 +366,26 @@ public abstract class ArrayUtils { } return array; } + + /** + * Use this instead of Arrays.asList(T... array) when you need a modifiable List. + * + * Returns a modifiable list containing the elements of the specified array. + * + * <p> + * Example usage: + * + * <pre> + * List<String> stooges = Arrays.asList("Larry", "Moe", "Curly"); + * stooges.remove("Curly"); + * </pre> + * + * @param <T> the class of the objects in the array + * @param array the array of elements to be added to the list + * @return a list containing the elements of the specified array + */ + public static <T> List<T> asList(T... array) { + return new ArrayList<>(Arrays.asList(array)); + } + } http://git-wip-us.apache.org/repos/asf/geode/blob/1f276d31/geode-core/src/test/java/org/apache/geode/internal/statistics/DiskSpaceLimitIntegrationTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/statistics/DiskSpaceLimitIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/statistics/DiskSpaceLimitIntegrationTest.java index 5d94fa0..c46817f 100644 --- a/geode-core/src/test/java/org/apache/geode/internal/statistics/DiskSpaceLimitIntegrationTest.java +++ b/geode-core/src/test/java/org/apache/geode/internal/statistics/DiskSpaceLimitIntegrationTest.java @@ -28,6 +28,7 @@ import org.apache.geode.StatisticsType; import org.apache.geode.internal.NanoTimer; import org.apache.geode.internal.io.MainWithChildrenRollingFileHandler; import org.apache.geode.internal.io.RollingFileHandler; +import org.apache.geode.internal.util.ArrayUtils; import org.apache.geode.test.junit.categories.IntegrationTest; import org.junit.After; import org.junit.Before; @@ -41,7 +42,6 @@ import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeoutException; @@ -65,7 +65,6 @@ public class DiskSpaceLimitIntegrationTest { private Statistics statistics; private RollingFileHandler testRollingFileHandler; - private MainWithChildrenRollingFileHandler mainWithChildrenRollingFileHandler; private SampleCollector sampleCollector; private StatArchiveHandlerConfig config; @@ -83,6 +82,7 @@ public class DiskSpaceLimitIntegrationTest { @Before public void setUp() throws Exception { this.dir = this.temporaryFolder.getRoot(); + this.dirOfDeletedFiles = this.temporaryFolder.newFolder("deleted"); this.name = this.testName.getMethodName(); @@ -108,13 +108,18 @@ public class DiskSpaceLimitIntegrationTest { when(this.config.getProductDescription()).thenReturn(this.testName.getMethodName()); this.testRollingFileHandler = new TestableRollingFileHandler(); - this.mainWithChildrenRollingFileHandler = new MainWithChildrenRollingFileHandler(); this.sampleCollector = new SampleCollector(sampler); this.initTimeStamp = NanoTimer.getTime(); this.timer.reset(); this.nanosTimeStamp = this.timer.getLastResetTime() - getNanoRate(); + + preConditions(); + } + + private void preConditions() throws Exception { + validateNumberFiles(0); } @After @@ -124,7 +129,6 @@ public class DiskSpaceLimitIntegrationTest { @Test public void zeroKeepsAllFiles() throws Exception { - this.dirOfDeletedFiles = this.temporaryFolder.newFolder("deleted"); this.sampleCollector.initialize(this.config, this.initTimeStamp, this.testRollingFileHandler); when(this.config.getArchiveDiskSpaceLimit()).thenReturn(0L); @@ -136,7 +140,6 @@ public class DiskSpaceLimitIntegrationTest { @Test public void aboveZeroDeletesOldestFile() throws Exception { - this.dirOfDeletedFiles = this.temporaryFolder.newFolder("deleted"); this.sampleCollector.initialize(this.config, this.initTimeStamp, this.testRollingFileHandler); when(this.config.getArchiveDiskSpaceLimit()).thenReturn(DISK_SPACE_LIMIT); @@ -161,16 +164,14 @@ public class DiskSpaceLimitIntegrationTest { @Test public void aboveZeroDeletesPreviousFiles() throws Exception { - assertThat(numberOfFiles(this.dir)).as("Unexpected files: " + listFiles(this.dir)).isEqualTo(0); - int oldMainId = 1; int newMainId = 2; int numberOfPreviousFiles = 100; int numberOfLines = 100; createPreviousFiles(oldMainId, numberOfPreviousFiles, numberOfLines); - assertThat(numberOfFiles(this.dir)).as("Missing files: " + listFiles(this.dir)) - .isEqualTo(numberOfPreviousFiles); + + validateNumberFiles(numberOfPreviousFiles); for (int childId = 1; childId <= numberOfPreviousFiles; childId++) { assertThat(archiveFile(oldMainId, childId)).exists(); @@ -186,8 +187,7 @@ public class DiskSpaceLimitIntegrationTest { when(this.config.getArchiveDiskSpaceLimit()) .thenReturn(sizeOfDirectory(this.dir) / numberOfPreviousFiles); - this.sampleCollector.initialize(this.config, this.initTimeStamp, - this.mainWithChildrenRollingFileHandler); + this.sampleCollector.initialize(this.config, this.initTimeStamp, this.testRollingFileHandler); assertThat(archiveFile()).exists().hasParent(this.dir); assertThat(markerFile(newMainId)).exists().hasParent(this.dir).hasBinaryContent(new byte[0]); @@ -199,8 +199,7 @@ public class DiskSpaceLimitIntegrationTest { sampleUntilFileExists(archiveFile(newMainId, 1)); assertThat(archiveFile(newMainId, 1)).exists(); - // this might be a brittle assertion... ok to delete if following for-block-assertion passes - assertThat(numberOfFiles(this.dir)).as("Unexpected files: " + listFiles(this.dir)).isEqualTo(2); + validateNumberFiles(2); for (int childId = 1; childId <= numberOfPreviousFiles; childId++) { assertThat(archiveFile(oldMainId, childId)).doesNotExist(); @@ -213,16 +212,14 @@ public class DiskSpaceLimitIntegrationTest { this.archiveFileName = new File(this.dir, this.name + ".gfs").getAbsolutePath(); when(this.config.getArchiveFileName()).thenReturn(new File(this.archiveFileName)); - assertThat(numberOfFiles(this.dir)).as("Unexpected files: " + listFiles(this.dir)).isEqualTo(0); - int oldMainId = 1; int newMainId = 2; int numberOfPreviousFiles = 100; int numberOfLines = 100; createPreviousFiles(oldMainId, numberOfPreviousFiles, numberOfLines); - assertThat(numberOfFiles(this.dir)).as("Missing files: " + listFiles(this.dir)) - .isEqualTo(numberOfPreviousFiles); + + validateNumberFiles(numberOfPreviousFiles); for (int childId = 1; childId <= numberOfPreviousFiles; childId++) { assertThat(archiveFile(oldMainId, childId)).exists(); @@ -238,8 +235,7 @@ public class DiskSpaceLimitIntegrationTest { when(this.config.getArchiveDiskSpaceLimit()) .thenReturn(sizeOfDirectory(this.dir) / numberOfPreviousFiles); - this.sampleCollector.initialize(this.config, this.initTimeStamp, - this.mainWithChildrenRollingFileHandler); + this.sampleCollector.initialize(this.config, this.initTimeStamp, this.testRollingFileHandler); assertThat(archiveFile()).exists().hasParent(this.dir); assertThat(markerFile(newMainId)).exists().hasParent(this.dir).hasBinaryContent(new byte[0]); @@ -252,13 +248,21 @@ public class DiskSpaceLimitIntegrationTest { assertThat(archiveFile(newMainId, 1)).exists(); // this might be a brittle assertion... ok to delete if following for-block-assertion passes - assertThat(numberOfFiles(this.dir)).as("Unexpected files: " + listFiles(this.dir)).isEqualTo(2); + validateNumberFiles(2); for (int childId = 1; childId <= numberOfPreviousFiles; childId++) { assertThat(archiveFile(oldMainId, childId)).doesNotExist(); } } + /** + * Validates number of files under this.dir while ignoring this.dirOfDeletedFiles. + */ + private void validateNumberFiles(final int expected) { + assertThat(numberOfFiles(this.dir)).as("Unexpected files: " + listFiles(this.dir)) + .isEqualTo(expected); + } + private void sampleNumberOfTimes(final int value) throws InterruptedException { long minutes = 1; long timeout = System.nanoTime() + MINUTES.toNanos(minutes); @@ -389,11 +393,13 @@ public class DiskSpaceLimitIntegrationTest { } private List<File> listFiles(final File dir) { - return Arrays.asList(dir.listFiles()); + List<File> files = ArrayUtils.asList(dir.listFiles()); + files.remove(this.dirOfDeletedFiles); + return files; } private int numberOfFiles(final File dir) { - return dir.listFiles().length; + return listFiles(dir).size(); } private void createPreviousFiles(final int mainId, final int fileCount, final int lineCount) http://git-wip-us.apache.org/repos/asf/geode/blob/1f276d31/geode-core/src/test/java/org/apache/geode/internal/util/ArrayUtilsJUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/util/ArrayUtilsJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/util/ArrayUtilsJUnitTest.java deleted file mode 100644 index 3ec8b12..0000000 --- a/geode-core/src/test/java/org/apache/geode/internal/util/ArrayUtilsJUnitTest.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more contributor license - * agreements. See the NOTICE file distributed with this work for additional information regarding - * copyright ownership. The ASF licenses this file to You 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 org.apache.geode.internal.util; - -import static org.junit.Assert.*; - -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import org.apache.geode.test.junit.categories.UnitTest; - -/** - * Unit tests for {@link ArrayUtils}. - * - * @since GemFire 7.x - */ -@Category(UnitTest.class) -public class ArrayUtilsJUnitTest { - - @Test - @SuppressWarnings("null") - public void testGetElementAtIndex() { - final Object[] array = {"test", "testing", "tested"}; - - assertEquals("test", ArrayUtils.getElementAtIndex(array, 0, null)); - assertEquals("testing", ArrayUtils.getElementAtIndex(array, 1, null)); - assertEquals("tested", ArrayUtils.getElementAtIndex(array, 2, null)); - } - - @Test - public void testGetElementAtIndexThrowingArrayIndexOutOfBoundsException() { - assertEquals("test", ArrayUtils.getElementAtIndex(new Object[0], 0, "test")); - } - - @Test - public void testGetElementAtIndexThrowingArrayIndexOutOfBoundsExceptionOnNonEmptyArray() { - assertEquals("defaultValue", - ArrayUtils.getElementAtIndex(new Object[] {"test"}, 1, "defaultValue")); - } - - @Test - public void testGetFirst() { - assertEquals("first", ArrayUtils.getFirst("first", "second", "third")); - assertEquals("null", ArrayUtils.getFirst("null", "nil", null)); - assertEquals("test", ArrayUtils.getFirst("test")); - assertNull(ArrayUtils.getFirst((Object[]) null)); - assertNull(ArrayUtils.getFirst(new Object[0])); - assertNull(ArrayUtils.getFirst(null, null, null)); - } - - @Test - public void testToString() { - final Object[] array = {"test", "testing", "tested"}; - - assertEquals("[test, testing, tested]", ArrayUtils.toString(array)); - } - - @Test - public void testToStringWithEmptyArray() { - assertEquals("[]", ArrayUtils.toString((new Object[0]))); - } - - @Test - public void testToStringWithNullArray() { - assertEquals("[]", ArrayUtils.toString((Object[]) null)); - } - - @Test - public void testGetIntegerArray() { - final Integer[] array = ArrayUtils.toIntegerArray(new int[] {0, 1, 2, 4, 8}); - - assertNotNull(array); - assertEquals(5, array.length); - assertEquals(0, array[0].intValue()); - assertEquals(1, array[1].intValue()); - assertEquals(2, array[2].intValue()); - assertEquals(4, array[3].intValue()); - assertEquals(8, array[4].intValue()); - } - - @Test - public void testGetIntegerArrayWithEmptyArray() { - final Integer[] array = ArrayUtils.toIntegerArray(new int[0]); - - assertNotNull(array); - assertEquals(0, array.length); - } - - @Test - @SuppressWarnings("null") - public void testGetIntegerArrayWithNullArray() { - final Integer[] array = ArrayUtils.toIntegerArray(null); - - assertNotNull(array); - assertEquals(0, array.length); - } - - @Test - public void testFromBytesToByteArray() { - int count = 0; - final byte[][] array = new byte[10][5]; - for (int i = 0; i < array.length; i++) { - for (int j = 0; j < array[i].length; j++) { - array[i][j] = (byte) ++count; - } - } - assertEquals(50, count); - - count = 0; - final Byte[][] byteArray = ArrayUtils.toByteArray(array); - for (int i = 0; i < byteArray.length; i++) { - for (int j = 0; j < byteArray[i].length; j++) { - assertEquals((byte) ++count, byteArray[i][j].byteValue()); - } - } - assertEquals(50, count); - } - - @Test - public void testFromByteArrayToBytes() { - int count = 100; - final Byte[][] byteArray = new Byte[5][10]; - for (int i = 0; i < byteArray.length; i++) { - for (int j = 0; j < byteArray[i].length; j++) { - byteArray[i][j] = (byte) --count; - } - } - assertEquals(50, count); - - count = 100; - final byte[][] array = ArrayUtils.toBytes(byteArray); - for (int i = 0; i < array.length; i++) { - for (int j = 0; j < array[i].length; j++) { - assertEquals((byte) --count, array[i][j]); - } - } - assertEquals(50, count); - } - - @Test - public void testFromEmptyBytesToByteArray() { - final byte[][] array = new byte[0][0]; - assertArrayEquals(new Byte[0][0], ArrayUtils.toByteArray(array)); - } - - @Test - public void testFromNullBytesToByteArray() { - final byte[][] array = null; - assertNull(ArrayUtils.toByteArray(array)); - } - - @Test - public void testFromEmptyByteArrayToBytes() { - final Byte[][] byteArray = new Byte[0][0]; - assertArrayEquals(new byte[0][0], ArrayUtils.toBytes(byteArray)); - } - - @Test - public void testFromNullByteArrayToBytes() { - final Byte[][] byteArray = null; - assertNull(ArrayUtils.toBytes(byteArray)); - } - -} http://git-wip-us.apache.org/repos/asf/geode/blob/1f276d31/geode-core/src/test/java/org/apache/geode/internal/util/ArrayUtilsTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/util/ArrayUtilsTest.java b/geode-core/src/test/java/org/apache/geode/internal/util/ArrayUtilsTest.java new file mode 100644 index 0000000..70da91b --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/util/ArrayUtilsTest.java @@ -0,0 +1,219 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You 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 org.apache.geode.internal.util; + +import static org.apache.geode.internal.util.ArrayUtils.*; +import static org.assertj.core.api.Assertions.*; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TestName; + +import java.util.Arrays; +import java.util.List; + +import org.apache.geode.test.junit.categories.UnitTest; + +/** + * Unit tests for {@link ArrayUtils}. + * + * @since GemFire 7.x + */ +@Category(UnitTest.class) +@SuppressWarnings("null") +public class ArrayUtilsTest { + + @Rule + public TestName testName = new TestName(); + + @Test + public void testGetElementAtIndex() { + Object[] arrayOfThree = new Object[] {"test", "testing", "tested"}; + + assertThat(getElementAtIndex(arrayOfThree, 0, null)).isEqualTo("test"); + assertThat(getElementAtIndex(arrayOfThree, 1, null)).isEqualTo("testing"); + assertThat(getElementAtIndex(arrayOfThree, 2, null)).isEqualTo("tested"); + } + + @Test + public void getElementAtIndex_emptyArray_returnsDefaultValue() { + Object[] emptyArray = new Object[] {}; + String defaultValue = this.testName.getMethodName(); + + assertThat(getElementAtIndex(emptyArray, 0, defaultValue)).isEqualTo(defaultValue); + } + + @Test + public void getElementAtIndex_emptyArray_returnsNullDefaultValue() { + Object[] emptyArray = new Object[] {}; + + assertThat(getElementAtIndex(emptyArray, 0, null)).isNull(); + } + + @Test + public void getElementAtIndex_indexOutOfBounds_returnsDefaultValue() { + Object[] arrayOfOne = new Object[] {"test"}; + String defaultValue = this.testName.getMethodName(); + + assertThat(getElementAtIndex(arrayOfOne, 2, defaultValue)).isEqualTo(defaultValue); + } + + @Test + public void getElementAtIndex_empty_indexOutOfBounds_returnsDefaultValue() { + Object[] emptyArray = new Object[] {}; + String defaultValue = this.testName.getMethodName(); + + assertThat(getElementAtIndex(emptyArray, 2, defaultValue)).isEqualTo(defaultValue); + } + + @Test + public void getFirst_array_returnsFirstElement() { + assertThat(getFirst("first", "second", "third")).isEqualTo("first"); + } + + @Test + public void getFirst_arrayContainingNull_returnsFirstElement() { + assertThat(getFirst("null", "nil", null)).isEqualTo("null"); + } + + @Test + public void getFirst_oneElement_returnsFirstElement() { + assertThat(getFirst("test")).isEqualTo("test"); + } + + @Test + public void getFirst_null_returnsNull() { + assertThat(getFirst((Object[]) null)).isNull(); + } + + @Test + public void getFirst_empty_returnsNull() { + assertThat(getFirst(new Object[0])).isNull(); + } + + @Test + public void getFirst_arrayOfNullValues_returnsNull() { + assertThat((Object) getFirst(null, null, null)).isNull(); + } + + @Test + public void toString_returnsOrderedStringInBrackets() { + Object[] arrayOfThree = new Object[] {"test", "testing", "tested"}; + + assertThat(ArrayUtils.toString(arrayOfThree)).isEqualTo("[test, testing, tested]"); + } + + @Test + public void toString_empty_returnsEmptyBrackets() { + assertThat(ArrayUtils.toString((new Object[0]))).isEqualTo("[]"); + } + + @Test + public void toString_null_returnsEmptyBrackets() { + assertThat(ArrayUtils.toString((Object[]) null)).isEqualTo("[]"); + } + + @Test + public void toIntegerArray_returnsOrderedArray() { + int[] sequence = new int[] {0, 1, 2, 4, 8}; + + assertThat(toIntegerArray(sequence)).isNotNull().hasSize(sequence.length).containsExactly(0, 1, + 2, 4, 8); + } + + @Test + public void toIntegerArray_empty_returnsEmptyArray() { + assertThat(toIntegerArray(new int[] {})).isNotNull().hasSize(0); + } + + @Test + public void toIntegerArray_null_returnsEmptyArray() { + assertThat(toIntegerArray(null)).isNotNull().hasSize(0); + } + + @Test + public void toByteArray_returnsBytes() { + int count = 0; + byte[][] array = new byte[10][5]; + for (int i = 0; i < array.length; i++) { + for (int j = 0; j < array[i].length; j++) { + array[i][j] = (byte) ++count; + } + } + assertThat(count).isEqualTo(50); + + count = 0; + Byte[][] byteArray = toByteArray(array); + for (int i = 0; i < byteArray.length; i++) { + for (int j = 0; j < byteArray[i].length; j++) { + assertThat(byteArray[i][j].byteValue()).isEqualTo((byte) ++count); + } + } + assertThat(count).isEqualTo(50); + } + + @Test + public void toBytes_returnsPrimitiveBytes() { + int count = 100; + Byte[][] byteArray = new Byte[5][10]; + for (int i = 0; i < byteArray.length; i++) { + for (int j = 0; j < byteArray[i].length; j++) { + byteArray[i][j] = (byte) --count; + } + } + assertThat(count).isEqualTo(50); + + count = 100; + byte[][] array = toBytes(byteArray); + for (int i = 0; i < array.length; i++) { + for (int j = 0; j < array[i].length; j++) { + assertThat(array[i][j]).isEqualTo((byte) --count); + } + } + assertThat(count).isEqualTo(50); + } + + @Test + public void toByteArray_empty_returnsEmptyBytes() { + byte[][] array = new byte[0][0]; + assertThat(toByteArray(array)).isEqualTo(new Byte[0][0]); + } + + @Test + public void toByteArray_null_returnsNull() { + byte[][] array = null; + assertThat(toByteArray(array)).isNull(); + } + + @Test + public void toBytes_empty_returnsEmpty() { + Byte[][] byteArray = new Byte[0][0]; + assertThat(toBytes(byteArray)).isEqualTo(new byte[0][0]); + } + + @Test + public void toBytes_null_returnsNull() { + Byte[][] byteArray = null; + assertThat(toBytes(byteArray)).isNull(); + } + + @Test + public void asList_returnsModifiableList() throws Exception { + List<String> modifiable = asList("Larry", "Moe", "Curly"); + assertThat(modifiable.remove("Curly")).isTrue(); + assertThat(modifiable).contains("Larry", "Moe").doesNotContain("Curly"); + } +}
