diff --git a/pom.xml b/pom.xml index cf720a9f..fe07ba7e 100644 --- a/pom.xml +++ b/pom.xml @@ -49,6 +49,12 @@ 4.12 test + + nl.jqno.equalsverifier + equalsverifier + 2.3.2 + test + diff --git a/src/main/java/com/mpatric/mp3agic/FileInputSource.java b/src/main/java/com/mpatric/mp3agic/FileInputSource.java new file mode 100644 index 00000000..80c2b192 --- /dev/null +++ b/src/main/java/com/mpatric/mp3agic/FileInputSource.java @@ -0,0 +1,43 @@ +package com.mpatric.mp3agic; + +import java.io.IOException; +import java.nio.channels.SeekableByteChannel; +import java.nio.file.Files; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.util.concurrent.TimeUnit; + +public class FileInputSource implements InputSource { + + private final Path path; + + public FileInputSource(Path path) { + this.path = path; + } + + @Override + public String getResourceName() { + return path.toString(); + } + + @Override + public boolean isReadable() { + return Files.exists(path) && Files.isReadable(path); + } + + @Override + public long getLastModified() throws IOException { + return Files.getLastModifiedTime(path).to(TimeUnit.MILLISECONDS); + } + + @Override + public long getLength() throws IOException { + return Files.size(path); + } + + @Override + public SeekableByteChannel openChannel(OpenOption... options) throws IOException { + return Files.newByteChannel(path, options); + } + +} diff --git a/src/main/java/com/mpatric/mp3agic/FileWrapper.java b/src/main/java/com/mpatric/mp3agic/FileWrapper.java index 11d15236..f12fa404 100644 --- a/src/main/java/com/mpatric/mp3agic/FileWrapper.java +++ b/src/main/java/com/mpatric/mp3agic/FileWrapper.java @@ -3,53 +3,57 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.nio.channels.SeekableByteChannel; import java.nio.file.Files; +import java.nio.file.OpenOption; import java.nio.file.Path; import java.nio.file.Paths; import java.util.concurrent.TimeUnit; public class FileWrapper { - protected Path path; - protected long length; + protected InputSource inputSource; protected long lastModified; protected FileWrapper() { } public FileWrapper(String filename) throws IOException { - this.path = Paths.get(filename); + if (filename == null) throw new IllegalArgumentException("filename must not be null"); + this.inputSource = new FileInputSource(Paths.get(filename)); init(); } public FileWrapper(File file) throws IOException { - if (file == null) throw new NullPointerException(); - this.path = Paths.get(file.getPath()); + if (file == null) throw new IllegalArgumentException("file must not be null"); + this.inputSource = new FileInputSource(Paths.get(file.getPath())); init(); } public FileWrapper(Path path) throws IOException { - if (path == null) throw new NullPointerException(); - this.path = path; + if (path == null) throw new IllegalArgumentException("path must not be null"); + this.inputSource = new FileInputSource(path); init(); } - private void init() throws IOException { - if (!Files.exists(path)) throw new FileNotFoundException("File not found " + path); - if (!Files.isReadable(path)) throw new IOException("File not readable"); - length = Files.size(path); - lastModified = Files.getLastModifiedTime(path).to(TimeUnit.MILLISECONDS); + public FileWrapper(InputSource inputSource) throws IOException { + if (inputSource == null) throw new IllegalArgumentException("inputSource must not be null"); + this.inputSource = inputSource; + init(); } - public String getFilename() { - return path.toString(); + private void init() throws IOException { + if (!inputSource.isReadable()) throw new FileNotFoundException("File could not be found or is not readable " + + inputSource.getResourceName()); + lastModified = inputSource.getLastModified(); } - public long getLength() { - return length; + public String getFilename() { + return inputSource.getResourceName(); } public long getLastModified() { return lastModified; } + } diff --git a/src/main/java/com/mpatric/mp3agic/ID3v1Tag.java b/src/main/java/com/mpatric/mp3agic/ID3v1Tag.java index 0818c199..e5fa244a 100644 --- a/src/main/java/com/mpatric/mp3agic/ID3v1Tag.java +++ b/src/main/java/com/mpatric/mp3agic/ID3v1Tag.java @@ -2,6 +2,7 @@ import java.io.UnsupportedEncodingException; import java.util.Arrays; +import java.util.Objects; public class ID3v1Tag implements ID3v1 { @@ -227,16 +228,7 @@ public void setComment(String comment) { @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((album == null) ? 0 : album.hashCode()); - result = prime * result + ((artist == null) ? 0 : artist.hashCode()); - result = prime * result + ((comment == null) ? 0 : comment.hashCode()); - result = prime * result + genre; - result = prime * result + ((title == null) ? 0 : title.hashCode()); - result = prime * result + ((track == null) ? 0 : track.hashCode()); - result = prime * result + ((year == null) ? 0 : year.hashCode()); - return result; + return Objects.hash(album, artist, comment, genre, title, track, year); } @Override @@ -247,39 +239,14 @@ public boolean equals(Object obj) { return false; if (getClass() != obj.getClass()) return false; - ID3v1Tag other = (ID3v1Tag) obj; - if (album == null) { - if (other.album != null) - return false; - } else if (!album.equals(other.album)) - return false; - if (artist == null) { - if (other.artist != null) - return false; - } else if (!artist.equals(other.artist)) - return false; - if (comment == null) { - if (other.comment != null) - return false; - } else if (!comment.equals(other.comment)) - return false; - if (genre != other.genre) - return false; - if (title == null) { - if (other.title != null) - return false; - } else if (!title.equals(other.title)) - return false; - if (track == null) { - if (other.track != null) - return false; - } else if (!track.equals(other.track)) - return false; - if (year == null) { - if (other.year != null) - return false; - } else if (!year.equals(other.year)) - return false; - return true; + final ID3v1Tag other = (ID3v1Tag) obj; + return + Objects.equals(album, other.album) && + Objects.equals(artist, other.artist) && + Objects.equals(comment, other.comment) && + Objects.equals(genre, other.genre) && + Objects.equals(title, other.title) && + Objects.equals(track, other.track) && + Objects.equals(year, other.year); } } diff --git a/src/main/java/com/mpatric/mp3agic/InputSource.java b/src/main/java/com/mpatric/mp3agic/InputSource.java new file mode 100644 index 00000000..9dc9e342 --- /dev/null +++ b/src/main/java/com/mpatric/mp3agic/InputSource.java @@ -0,0 +1,35 @@ +package com.mpatric.mp3agic; + +import java.io.IOException; +import java.nio.channels.SeekableByteChannel; +import java.nio.file.OpenOption; + +public interface InputSource { + + /** + * Retrieves a value that identifies this resource. + * Can be a URL or a file name, for example. + */ + String getResourceName(); + + /** + * Tells if the resource is valid and readable. + */ + boolean isReadable(); + + /** + * Retrieves the last modification time of the resource. + */ + long getLastModified() throws IOException; + + /** + * Retrieves the length of the resource in bytes. + */ + long getLength() throws IOException; + + /** + * Opens a channel to read the resource. + */ + SeekableByteChannel openChannel(OpenOption... options) throws IOException; + +} diff --git a/src/main/java/com/mpatric/mp3agic/Mp3File.java b/src/main/java/com/mpatric/mp3agic/Mp3File.java index 9b858458..b5428c26 100644 --- a/src/main/java/com/mpatric/mp3agic/Mp3File.java +++ b/src/main/java/com/mpatric/mp3agic/Mp3File.java @@ -84,13 +84,18 @@ public Mp3File(Path path, int bufferLength, boolean scanFile) throws IOException init(bufferLength, scanFile); } + public Mp3File(InputSource inputSource, int bufferLength, boolean scanFile) throws IOException, UnsupportedTagException, InvalidDataException { + super(inputSource); + init(bufferLength, scanFile); + } + private void init(int bufferLength, boolean scanFile) throws IOException, UnsupportedTagException, InvalidDataException { if (bufferLength < MINIMUM_BUFFER_LENGTH + 1) throw new IllegalArgumentException("Buffer too small"); this.bufferLength = bufferLength; this.scanFile = scanFile; - try (SeekableByteChannel seekableByteChannel = Files.newByteChannel(path, StandardOpenOption.READ)) { + try (SeekableByteChannel seekableByteChannel = inputSource.openChannel(StandardOpenOption.READ)) { initId3v1Tag(seekableByteChannel); scanFile(seekableByteChannel); if (startOffset < 0) { @@ -146,7 +151,7 @@ private void scanFile(SeekableByteChannel seekableByteChannel) throws IOExceptio } lastOffset = startOffset; } - offset = scanBlock(bytes, bytesRead, fileOffset, offset); + offset = scanBlock(bytes, bytesRead, fileOffset, offset, seekableByteChannel.size()); fileOffset += offset; seekableByteChannel.position(fileOffset); break; @@ -204,12 +209,12 @@ private int scanBlockForStart(byte[] bytes, int bytesRead, int absoluteOffset, i return offset; } - private int scanBlock(byte[] bytes, int bytesRead, int absoluteOffset, int offset) throws InvalidDataException { + private int scanBlock(byte[] bytes, int bytesRead, int absoluteOffset, int offset, long size) throws InvalidDataException { while (offset < bytesRead - MINIMUM_BUFFER_LENGTH) { MpegFrame frame = new MpegFrame(bytes[offset], bytes[offset + 1], bytes[offset + 2], bytes[offset + 3]); - sanityCheckFrame(frame, absoluteOffset + offset); + sanityCheckFrame(frame, absoluteOffset + offset, size); int newEndOffset = absoluteOffset + offset + frame.getLengthInBytes() - 1; - if (newEndOffset < maxEndOffset()) { + if (newEndOffset < maxEndOffset(size)) { endOffset = absoluteOffset + offset + frame.getLengthInBytes() - 1; frameCount++; addBitrate(frame.getBitrate()); @@ -221,8 +226,8 @@ private int scanBlock(byte[] bytes, int bytesRead, int absoluteOffset, int offse return offset; } - private int maxEndOffset() { - int maxEndOffset = (int) getLength(); + private int maxEndOffset(long size) { + int maxEndOffset = (int) size; if (hasId3v1Tag()) maxEndOffset -= ID3v1Tag.TAG_LENGTH; return maxEndOffset; } @@ -249,11 +254,11 @@ private boolean isXingFrame(byte[] bytes, int offset) { return false; } - private void sanityCheckFrame(MpegFrame frame, int offset) throws InvalidDataException { + private void sanityCheckFrame(MpegFrame frame, int offset, long size) throws InvalidDataException { if (sampleRate != frame.getSampleRate()) throw new InvalidDataException("Inconsistent frame header"); if (!layer.equals(frame.getLayer())) throw new InvalidDataException("Inconsistent frame header"); if (!version.equals(frame.getVersion())) throw new InvalidDataException("Inconsistent frame header"); - if (offset + frame.getLengthInBytes() > getLength()) + if (offset + frame.getLengthInBytes() > size) throw new InvalidDataException("Frame would extend beyond end of file"); } @@ -270,7 +275,7 @@ private void addBitrate(int bitrate) { private void initId3v1Tag(SeekableByteChannel seekableByteChannel) throws IOException { ByteBuffer byteBuffer = ByteBuffer.allocate(ID3v1Tag.TAG_LENGTH); - seekableByteChannel.position(getLength() - ID3v1Tag.TAG_LENGTH); + seekableByteChannel.position(seekableByteChannel.size() - ID3v1Tag.TAG_LENGTH); byteBuffer.clear(); int bytesRead = seekableByteChannel.read(byteBuffer); if (bytesRead < ID3v1Tag.TAG_LENGTH) throw new IOException("Not enough bytes read"); @@ -302,7 +307,7 @@ private void initId3v2Tag(SeekableByteChannel seekableByteChannel) throws IOExce } private void initCustomTag(SeekableByteChannel seekableByteChannel) throws IOException { - int bufferLength = (int) (getLength() - (endOffset + 1)); + int bufferLength = (int) (seekableByteChannel.size() - (endOffset + 1)); if (hasId3v1Tag()) bufferLength -= ID3v1Tag.TAG_LENGTH; if (bufferLength <= 0) { customTag = null; @@ -442,10 +447,13 @@ public void removeCustomTag() { } public void save(String newFilename) throws IOException, NotSupportedException { - if (path.toAbsolutePath().compareTo(Paths.get(newFilename).toAbsolutePath()) == 0) { + final Path originalPath = Paths.get(inputSource.getResourceName()).toAbsolutePath(); + final Path newPath = Paths.get(newFilename).toAbsolutePath(); + if (originalPath.compareTo(newPath) == 0) { throw new IllegalArgumentException("Save filename same as source filename"); } - try (SeekableByteChannel saveFile = Files.newByteChannel(Paths.get(newFilename), EnumSet.of(StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE))) { + try (SeekableByteChannel saveFile = Files.newByteChannel(newPath, + EnumSet.of(StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE))) { if (hasId3v2Tag()) { ByteBuffer byteBuffer = ByteBuffer.wrap(id3v2Tag.toBytes()); byteBuffer.rewind(); @@ -471,9 +479,8 @@ private void saveMpegFrames(SeekableByteChannel saveFile) throws IOException { if (filePos < 0) filePos = startOffset; if (filePos < 0) return; if (endOffset < filePos) return; - SeekableByteChannel seekableByteChannel = Files.newByteChannel(path, StandardOpenOption.READ); ByteBuffer byteBuffer = ByteBuffer.allocate(bufferLength); - try { + try (SeekableByteChannel seekableByteChannel = inputSource.openChannel(StandardOpenOption.READ)) { seekableByteChannel.position(filePos); while (true) { byteBuffer.clear(); @@ -489,8 +496,6 @@ private void saveMpegFrames(SeekableByteChannel saveFile) throws IOException { break; } } - } finally { - seekableByteChannel.close(); } } } diff --git a/src/main/java/com/mpatric/mp3agic/MutableInteger.java b/src/main/java/com/mpatric/mp3agic/MutableInteger.java index d2c8b6fe..7c4f1163 100644 --- a/src/main/java/com/mpatric/mp3agic/MutableInteger.java +++ b/src/main/java/com/mpatric/mp3agic/MutableInteger.java @@ -1,5 +1,7 @@ package com.mpatric.mp3agic; +import java.util.Objects; + public class MutableInteger { private int value; @@ -22,10 +24,7 @@ public void setValue(int value) { @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + value; - return result; + return Objects.hash(value); } @Override @@ -36,9 +35,7 @@ public boolean equals(Object obj) { return false; if (getClass() != obj.getClass()) return false; - MutableInteger other = (MutableInteger) obj; - if (value != other.value) - return false; - return true; + final MutableInteger other = (MutableInteger) obj; + return Objects.equals(value, other.value); } } diff --git a/src/test/java/com/mpatric/mp3agic/FileWrapperTest.java b/src/test/java/com/mpatric/mp3agic/FileWrapperTest.java index 15f66994..47c9dd33 100644 --- a/src/test/java/com/mpatric/mp3agic/FileWrapperTest.java +++ b/src/test/java/com/mpatric/mp3agic/FileWrapperTest.java @@ -24,7 +24,7 @@ public void shouldReadValidFilename() throws IOException { System.out.println(VALID_FILENAME); assertEquals(fileWrapper.getFilename(), VALID_FILENAME); assertTrue(fileWrapper.getLastModified() > 0); - assertEquals(fileWrapper.getLength(), VALID_FILE_LENGTH); + assertEquals(fileWrapper.inputSource.getLength(), VALID_FILE_LENGTH); } @Test @@ -34,7 +34,7 @@ public void shouldReadValidFile() throws IOException { System.out.println(VALID_FILENAME); assertEquals(fileWrapper.getFilename(), VALID_FILENAME); assertTrue(fileWrapper.getLastModified() > 0); - assertEquals(fileWrapper.getLength(), VALID_FILE_LENGTH); + assertEquals(fileWrapper.inputSource.getLength(), VALID_FILE_LENGTH); } @Test @@ -44,7 +44,7 @@ public void shouldReadValidPath() throws IOException { System.out.println(VALID_FILENAME); assertEquals(fileWrapper.getFilename(), VALID_FILENAME); assertTrue(fileWrapper.getLastModified() > 0); - assertEquals(fileWrapper.getLength(), VALID_FILE_LENGTH); + assertEquals(fileWrapper.inputSource.getLength(), VALID_FILE_LENGTH); } @Test(expected = FileNotFoundException.class) @@ -57,18 +57,23 @@ public void shouldFailForMalformedFilename() throws IOException { new FileWrapper(MALFORMED_FILENAME); } - @Test(expected = NullPointerException.class) + @Test(expected = IllegalArgumentException.class) public void shouldFailForNullFilename() throws IOException { new FileWrapper((String) null); } - @Test(expected = NullPointerException.class) + @Test(expected = IllegalArgumentException.class) public void shouldFailForNullFilenameFile() throws IOException { new FileWrapper((java.io.File) null); } - @Test(expected = NullPointerException.class) + @Test(expected = IllegalArgumentException.class) public void shouldFailForNullPath() throws IOException { new FileWrapper((java.nio.file.Path) null); } + + @Test(expected = IllegalArgumentException.class) + public void shouldFailForNullInputSource() throws IOException { + new FileWrapper((InputSource) null); + } } diff --git a/src/test/java/com/mpatric/mp3agic/ID3v1TagTest.java b/src/test/java/com/mpatric/mp3agic/ID3v1TagTest.java index e2fbba13..07ee932a 100644 --- a/src/test/java/com/mpatric/mp3agic/ID3v1TagTest.java +++ b/src/test/java/com/mpatric/mp3agic/ID3v1TagTest.java @@ -1,5 +1,7 @@ package com.mpatric.mp3agic; +import nl.jqno.equalsverifier.EqualsVerifier; +import nl.jqno.equalsverifier.Warning; import org.junit.Test; import static org.junit.Assert.*; @@ -161,4 +163,37 @@ public void shouldReturnEmptyTrackIfNotSetOn11Tag() throws Exception { ID3v1 id3tag = new ID3v1Tag(tagBuffer); assertEquals("", id3tag.getTrack()); } + + @Test + public void shouldReturnCorrectGenreDescription() throws Exception { + for (int genre = 0; genre < ID3v1Genres.GENRES.length; ++genre) { + final ID3v1 id3tag = new ID3v1Tag(); + id3tag.setGenre(genre); + assertEquals(ID3v1Genres.GENRES[genre], id3tag.getGenreDescription()); + } + } + + @Test + public void shouldReturnUnknownGenreDescriptionForOutOfRangeGenre() throws Exception { + final ID3v1 id3tag = new ID3v1Tag(); + id3tag.setGenre(Integer.MAX_VALUE); + assertEquals("Unknown", id3tag.getGenreDescription()); + } + + @Test + public void shouldReturnCorrectVersion() throws Exception { + final ID3v1 id3tag1 = new ID3v1Tag(); + assertEquals("0", id3tag1.getVersion()); + final ID3v1 id3tag2 = new ID3v1Tag(); + id3tag2.setTrack("1"); + assertEquals("1", id3tag2.getVersion()); + } + + @Test + public void shouldCorrectlyImplementHashCodeAndEquals() throws Exception { + EqualsVerifier.forClass(ID3v1Tag.class) + .usingGetClass() + .suppress(Warning.NONFINAL_FIELDS) + .verify(); + } } diff --git a/src/test/java/com/mpatric/mp3agic/Mp3FileTest.java b/src/test/java/com/mpatric/mp3agic/Mp3FileTest.java index f8657b8d..1cd90dd9 100644 --- a/src/test/java/com/mpatric/mp3agic/Mp3FileTest.java +++ b/src/test/java/com/mpatric/mp3agic/Mp3FileTest.java @@ -5,9 +5,11 @@ import java.io.File; import java.io.IOException; import java.nio.channels.SeekableByteChannel; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; +import java.util.Arrays; import static junit.framework.TestCase.assertFalse; import static org.junit.Assert.*; @@ -204,6 +206,29 @@ private void testShouldInitialiseProperlyWhenNotScanningFile(Mp3File mp3File) th assertTrue(mp3File.hasId3v2Tag()); } + @Test + public void shouldSetId3v1Tag() throws Exception { + final Mp3File mp3File = new Mp3File(MP3_WITH_NO_TAGS); + final ID3v1 id3tag = new ID3v1Tag(); + id3tag.setTrack("5"); + id3tag.setArtist("ARTIST"); + id3tag.setTitle("TITLE"); + id3tag.setAlbum("ALBUM"); + id3tag.setYear("1997"); + id3tag.setGenre(13); + id3tag.setComment(""); + String saveFilename = mp3File.getFilename() + ".copy"; + try { + mp3File.setId3v1Tag(id3tag); + mp3File.save(saveFilename); + Mp3File newMp3File = new Mp3File(saveFilename); + assertTrue(newMp3File.hasId3v1Tag()); + assertEquals(id3tag, newMp3File.getId3v1Tag()); + } finally { + TestHelper.deleteFile(saveFilename); + } + } + @Test public void shouldRemoveId3v1Tag() throws Exception { String filename = MP3_WITH_ID3V1_AND_ID3V23_AND_CUSTOM_TAGS; @@ -230,6 +255,27 @@ private void testShouldRemoveId3v1Tag(Mp3File mp3File) throws Exception { } } + @Test + public void shouldSetId3v2Tag() throws Exception { + final Mp3File mp3File = new Mp3File(MP3_WITH_NO_TAGS); + final ID3v2 id3tag = new ID3v24Tag(); + id3tag.setArtist("ARTIST"); + id3tag.setTitle("TITLE"); + id3tag.setAlbum("ALBUM"); + id3tag.setYear("1954"); + id3tag.setGenre(0x0d); + String saveFilename = mp3File.getFilename() + ".copy"; + try { + mp3File.setId3v2Tag(id3tag); + mp3File.save(saveFilename); + Mp3File newMp3File = new Mp3File(saveFilename); + assertTrue(newMp3File.hasId3v2Tag()); + assertEquals(id3tag, newMp3File.getId3v2Tag()); + } finally { + TestHelper.deleteFile(saveFilename); + } + } + @Test public void shouldRemoveId3v2Tag() throws Exception { String filename = MP3_WITH_ID3V1_AND_ID3V23_AND_CUSTOM_TAGS; @@ -256,6 +302,22 @@ private void testShouldRemoveId3v2Tag(Mp3File mp3File) throws Exception { } } + @Test + public void shouldSetCustomTag() throws Exception { + final Mp3File mp3File = new Mp3File(MP3_WITH_NO_TAGS); + final byte[] customTag = "CUSTOM_TAG".getBytes(StandardCharsets.UTF_8); + String saveFilename = mp3File.getFilename() + ".copy"; + try { + mp3File.setCustomTag(customTag); + mp3File.save(saveFilename); + Mp3File newMp3File = new Mp3File(saveFilename); + assertTrue(newMp3File.hasCustomTag()); + assertTrue(Arrays.equals(newMp3File.getCustomTag(), customTag)); + } finally { + TestHelper.deleteFile(saveFilename); + } + } + @Test public void shouldRemoveCustomTag() throws Exception { String filename = MP3_WITH_ID3V1_AND_ID3V23_AND_CUSTOM_TAGS; @@ -294,6 +356,18 @@ public void shouldRemoveId3v1AndId3v2AndCustomTagsForFileConstructor() throws Ex testShouldRemoveId3v1AndId3v2AndCustomTags(new Mp3File(filename)); } + @Test + public void shouldReturnCorrectLengthInSeconds() throws Exception { + final Mp3File mp3File = new Mp3File(MP3_WITH_ID3V1_AND_ID3V23_TAGS); + assertEquals(0, mp3File.getLengthInSeconds()); + } + + @Test + public void shouldCorrectlyIdentifyIfVBR() throws Exception { + final Mp3File mp3File = new Mp3File(MP3_WITH_ID3V1_AND_ID3V23_TAGS); + assertTrue(mp3File.isVbr()); + } + private void testShouldRemoveId3v1AndId3v2AndCustomTags(Mp3File mp3File) throws Exception { String saveFilename = mp3File.getFilename() + ".copy"; try { diff --git a/src/test/java/com/mpatric/mp3agic/MutableIntegerTest.java b/src/test/java/com/mpatric/mp3agic/MutableIntegerTest.java index 46679d39..a67198cb 100644 --- a/src/test/java/com/mpatric/mp3agic/MutableIntegerTest.java +++ b/src/test/java/com/mpatric/mp3agic/MutableIntegerTest.java @@ -1,5 +1,7 @@ package com.mpatric.mp3agic; +import nl.jqno.equalsverifier.EqualsVerifier; +import nl.jqno.equalsverifier.Warning; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -28,47 +30,10 @@ public void setsValue() { } @Test - public void equalsItself() { - MutableInteger integer = new MutableInteger(8); - assertEquals(integer, integer); - } - - @Test - public void equalIfValueEqual() { - MutableInteger eight = new MutableInteger(8); - MutableInteger eightAgain = new MutableInteger(8); - assertEquals(eight, eightAgain); - } - - @Test - public void notEqualToNull() { - MutableInteger integer = new MutableInteger(8); - assertFalse(integer.equals(null)); - } - - @Test - public void notEqualToDifferentClass() { - MutableInteger integer = new MutableInteger(8); - assertFalse(integer.equals("8")); - } - - @Test - public void notEqualIfValueNotEqual() { - MutableInteger eight = new MutableInteger(8); - MutableInteger nine = new MutableInteger(9); - assertNotEquals(eight, nine); - } - - @Test - public void hashCodeIsConsistent() { - MutableInteger integer = new MutableInteger(8); - assertEquals(integer.hashCode(), integer.hashCode()); - } - - @Test - public void equalObjectsHaveSameHashCode() { - MutableInteger eight = new MutableInteger(8); - MutableInteger eightAgain = new MutableInteger(8); - assertEquals(eight.hashCode(), eightAgain.hashCode()); + public void shouldCorrectlyImplementHashCodeAndEquals() throws Exception { + EqualsVerifier.forClass(MutableInteger.class) + .usingGetClass() + .suppress(Warning.NONFINAL_FIELDS) + .verify(); } }