public String encryptFilename(final BaseEncoding encoding, final String cleartextName, final byte[] associatedData) {
        final CacheKey key = new CacheKey(encoding, cleartextName, associatedData);
        if(encryptCache.contains(key)) {
            return encryptCache.get(key);
        }
        final String ciphertextName = impl.encryptFilename(encoding, cleartextName, associatedData);
        encryptCache.put(key, ciphertextName);
        decryptCache.put(new CacheKey(encoding, ciphertextName, associatedData), cleartextName);
        return ciphertextName;
    }
@Test
    public void TestEncryptFilename() {
        final FileNameCryptor mock = mock(FileNameCryptor.class);
        final CryptorCache cryptor = new CryptorCache(mock);
        when(mock.encryptFilename(any(), any(), any())).thenReturn(RandomStringUtils.randomAscii(10));
        final String encrypted1 = cryptor.encryptFilename(CryptorCache.BASE32, "first", "id1".getBytes());
        verify(mock, times(1)).encryptFilename(any(), any(), any());
        assertEquals(encrypted1, cryptor.encryptFilename(CryptorCache.BASE32, "first", "id1".getBytes()));
        verify(mock, times(1)).encryptFilename(any(), any(), any());
        // ensure using reverse cache from encryption
        assertEquals("first", cryptor.decryptFilename(CryptorCache.BASE32, encrypted1, "id1".getBytes()));
        verify(mock, times(1)).encryptFilename(any(), any(), any());
        verifyNoMoreInteractions(mock);
        // cache miss on encoding
        cryptor.encryptFilename(BaseEncoding.base64Url(), "first", "id1".getBytes());
        verify(mock, times(2)).encryptFilename(any(), any(), any());
        // cache miss on cleartext
        cryptor.encryptFilename(CryptorCache.BASE32, "second", "id1".getBytes());
        verify(mock, times(3)).encryptFilename(any(), any(), any());
        // cache miss on byte[]
        cryptor.encryptFilename(CryptorCache.BASE32, "first", "id2".getBytes());
        verify(mock, times(4)).encryptFilename(any(), any(), any());
    }