package org.dcache.util; import com.google.common.base.Joiner; import com.google.common.base.Splitter; import com.google.common.collect.Sets; import org.hamcrest.Description; import org.hamcrest.TypeSafeMatcher; import org.junit.Test; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Set; import static com.google.common.base.Preconditions.checkNotNull; import static org.dcache.util.ChecksumType.*; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; public class ChecksumsTests { private String _rfc3230; private Collection<Checksum> _checksums; @Test public void shouldGiveEmptyStringForSetOfUnsupportedType() { givenSet(checksum().ofType(MD4_TYPE). withValue("6df23dc03f9b54cc38a0fc1483df6e21")); whenGeneratingRfc3230ForSetOfChecksums(); assertThat(_rfc3230, equalTo("")); } @Test public void shouldGiveEmptyStringForEmptySetOfChecksums() { givenSet(); whenGeneratingRfc3230ForSetOfChecksums(); assertThat(_rfc3230, equalTo("")); } @Test public void shouldGiveCorrectStringForSetOfAdler32() { givenSet(checksum().ofType(ADLER32).withValue("3da0195")); whenGeneratingRfc3230ForSetOfChecksums(); assertThat(_rfc3230, equalTo("adler32=03da0195")); } @Test public void shouldGiveCorrectStringForSetOfMd5() { givenSet(checksum().ofType(MD5_TYPE). withValue("1d45d92d02ccb88fca6792837093dc38")); whenGeneratingRfc3230ForSetOfChecksums(); assertThat(_rfc3230, equalTo("md5=HUXZLQLMuI/KZ5KDcJPcOA==")); } @Test public void shouldGiveCorrectStringForAdler32AndMD5() { givenSet(checksum().ofType(ADLER32).withValue("3da0195"), checksum().ofType(MD5_TYPE). withValue("1d45d92d02ccb88fca6792837093dc38")); whenGeneratingRfc3230ForSetOfChecksums(); assertThat(_rfc3230, hasOnlyParts("adler32=03da0195", "md5=HUXZLQLMuI/KZ5KDcJPcOA==")); } @Test public void shouldGiveCorrectStringForUnsupportedAndAdler32AndMD5() { givenSet(checksum().ofType(MD4_TYPE). withValue("6df23dc03f9b54cc38a0fc1483df6e21"), checksum().ofType(ADLER32).withValue("3da0195"), checksum().ofType(MD5_TYPE). withValue("1d45d92d02ccb88fca6792837093dc38")); whenGeneratingRfc3230ForSetOfChecksums(); assertThat(_rfc3230, hasOnlyParts("adler32=03da0195", "md5=HUXZLQLMuI/KZ5KDcJPcOA==")); } @Test public void shouldReturnEmptySetDecodingNull() { Set<Checksum> result = Checksums.decodeRfc3230(null); assertThat(result, empty()); } @Test public void shouldReturnEmptySetDecodingEmptyString() { Set<Checksum> result = Checksums.decodeRfc3230(""); assertThat(result, empty()); } @Test public void shouldReturnSingleChecksumForAdler32String() { Set<Checksum> result = Checksums.decodeRfc3230("adler32=03da0195"); Set<Checksum> expected = Collections.singleton(new Checksum(ChecksumType.ADLER32, "03da0195")); assertThat(result, equalTo(expected)); } @Test public void shouldReturnSingleChecksumForAdler32StringWithWhiteSpace() { Set<Checksum> result = Checksums.decodeRfc3230(" adler32=03da0195 "); Set<Checksum> expected = Collections.singleton(new Checksum(ChecksumType.ADLER32, "03da0195")); assertThat(result, equalTo(expected)); } @Test public void shouldReturnSingleChecksumForCapitalAdler32String() { Set<Checksum> result = Checksums.decodeRfc3230("ADLER32=03DA0195"); Set<Checksum> expected = Collections.singleton(new Checksum(ChecksumType.ADLER32, "03DA0195")); assertThat(result, equalTo(expected)); } @Test public void shouldReturnSingleChecksumForMd5String() { Set<Checksum> result = Checksums.decodeRfc3230("md5=HUXZLQLMuI/KZ5KDcJPcOA=="); Set<Checksum> expected = Collections.singleton( new Checksum(ChecksumType.MD5_TYPE, "1d45d92d02ccb88fca6792837093dc38")); assertThat(result, equalTo(expected)); } @Test public void shouldReturnEmptySetForMalformedMd5String() { Set<Checksum> result = Checksums.decodeRfc3230("md5=THIS-IS-NOT-VALID-DIGEST"); assertThat(result, empty()); } @Test public void shouldReturnSingleChecksumForMd5StringWithSpace() { Set<Checksum> result = Checksums.decodeRfc3230(" md5=HUXZLQLMuI/KZ5KDcJPcOA== "); Set<Checksum> expected = Collections.singleton( new Checksum(ChecksumType.MD5_TYPE, "1d45d92d02ccb88fca6792837093dc38")); assertThat(result, equalTo(expected)); } @Test public void shouldReturnSingleChecksumForCapitalMd5String() { Set<Checksum> result = Checksums.decodeRfc3230("MD5=HUXZLQLMuI/KZ5KDcJPcOA=="); Set<Checksum> expected = Collections.singleton( new Checksum(ChecksumType.MD5_TYPE, "1d45d92d02ccb88fca6792837093dc38")); assertThat(result, equalTo(expected)); } @Test public void shouldReturnBothForMd5AndAdler32() { Set<Checksum> result = Checksums.decodeRfc3230("adler32=03da0195,md5=HUXZLQLMuI/KZ5KDcJPcOA=="); Set<Checksum> expected = Sets.newHashSet(newAdler32Checksum("03da0195"), newMd5Checksum("1d45d92d02ccb88fca6792837093dc38")); assertThat(result, equalTo(expected)); } @Test public void shouldReturnBothForAdler32AndMd5() { Set<Checksum> result = Checksums.decodeRfc3230("md5=HUXZLQLMuI/KZ5KDcJPcOA==,adler32=03da0195"); Set<Checksum> expected = Sets.newHashSet(newAdler32Checksum("03da0195"), newMd5Checksum("1d45d92d02ccb88fca6792837093dc38")); assertThat(result, equalTo(expected)); } @Test public void shouldReturnBothForAdler32AndMd5WithSpaces() { Set<Checksum> result = Checksums.decodeRfc3230(" md5=HUXZLQLMuI/KZ5KDcJPcOA==,adler32=03da0195 "); Set<Checksum> expected = Sets.newHashSet(newAdler32Checksum("03da0195"), newMd5Checksum("1d45d92d02ccb88fca6792837093dc38")); assertThat(result, equalTo(expected)); } @Test public void shouldReturnBothForAdler32AndMd5AndUnknown() { Set<Checksum> result = Checksums.decodeRfc3230("md5=HUXZLQLMuI/KZ5KDcJPcOA==,adler32=03da0195,unknown=UNKNOWN-VALUE"); Set<Checksum> expected = Sets.newHashSet(newAdler32Checksum("03da0195"), newMd5Checksum("1d45d92d02ccb88fca6792837093dc38")); assertThat(result, equalTo(expected)); } private Checksum newMd5Checksum(String value) { return new Checksum(ChecksumType.MD5_TYPE, value); } private Checksum newAdler32Checksum(String value) { return new Checksum(ChecksumType.ADLER32, value); } private void givenSet(ChecksumBuilder... builders) { _checksums = new HashSet<>(); for(ChecksumBuilder builder : builders) { _checksums.add(builder.build()); } } private void whenGeneratingRfc3230ForSetOfChecksums() { _rfc3230 = Checksums.TO_RFC3230.apply(_checksums); } private ChecksumBuilder checksum() { return new ChecksumBuilder(); } private class ChecksumBuilder { private ChecksumType _type; private String _value; public ChecksumBuilder ofType(ChecksumType type) { checkNotNull(type); _type = type; return this; } public ChecksumBuilder withValue(String value) { checkNotNull(value); _value = value; return this; } public Checksum build() { checkNotNull(_value); checkNotNull(_type); return new Checksum(_type, _value); } } private static HasOnlyParts hasOnlyParts(String... parts) { return new HasOnlyParts(parts); } /** * Matcher that passes if the supplied comma-separated list of parts * contains all of the matching parts and nothing else. The order of * the parts does not matter. */ private static class HasOnlyParts extends TypeSafeMatcher<String> { private Set<String> _needles = new HashSet<>(); private String _missing; private String _extra; public HasOnlyParts(String... parts) { _needles.addAll(Arrays.asList(parts)); } @Override protected boolean matchesSafely(String t) { Set<String> haystack = Sets.newHashSet(Splitter.on(',').split(t)); if(!haystack.containsAll(_needles)) { _needles.removeAll(haystack); _missing = Joiner.on(", ").join(_needles); return false; } if(!_needles.containsAll(haystack)) { haystack.removeAll(_needles); _extra = Joiner.on(", ").join(haystack); return false; } return true; } @Override public void describeTo(Description d) { if(_missing != null) { d.appendText("missing: ").appendValue(_missing); } else { d.appendText("unexpected: ").appendValue(_extra); } } } }