// Path: src/main/java/com/thoughtworks/go/strongauth/authentication/principalDetailSources/ConfigurableUserPrincipalDetailSource.java
// public class ConfigurableUserPrincipalDetailSource implements PrincipalDetailSource {
//     private final Map<String, PrincipalDetail> principalDetails = new HashMap<>();
//     public static final Pattern DETAIL_PATTERN = Pattern.compile("^([^:]+):([^:]+):([^:]*):([^:]+)$");
// 
//     private static final Logger LOGGER = Logger.getLoggerFor(ConfigurableUserPrincipalDetailSource.class);
//     public final String pluginId = Constants.PLUGIN_ID;
// 
//     public ConfigurableUserPrincipalDetailSource(InputStreamSource passwordSource) {
//         try {
//             loadSource(passwordSource.inputStream());
//         } catch (IOException e) {
//             LOGGER.warn("Missing password file. No credentials loaded.");
//         }
// 
//         passwordSource.addChangeListener(new SourceChangeListener() {
//             @Override
//             public void sourceChanged(SourceChangeEvent event) {
//                 try {
//                     loadSource(event.getInputStream());
//                 } catch (IOException e) {
//                     LOGGER.error("Missing password file. No credentials loaded.");
//                 }
//             }
//         });
//     }
// 
//     private void loadSource(InputStream passwordFile) throws IOException {
//         principalDetails.clear();
//         String line;
//         final BufferedReader bufferedReader = toBufferedReader(new InputStreamReader(passwordFile));
//         while ((line = bufferedReader.readLine()) != null) {
//             Optional<PrincipalDetail> maybeDetail = parse(line);
//             if (maybeDetail.isPresent()) {
//                 PrincipalDetail detail = maybeDetail.get();
//                 principalDetails.put(detail.getUsername(), detail);
//             }
//         }
//     }
// 
//     private Optional<PrincipalDetail> parse(final String line) {
//         final Matcher matcher = DETAIL_PATTERN.matcher(line);
//         if (matcher.find()) {
//             return Optional.of(new PrincipalDetail(
//                     matcher.group(1),
//                     matcher.group(2),
//                     matcher.group(3),
//                     matcher.group(4))
//             );
//         } else {
//             LOGGER.warn(format("Failed to parse password file line %s", line));
//             return Optional.absent();
//         }
//     }
// 
//     @Override
//     public Optional<PrincipalDetail> byUsername(String username) {
//         return Optional.fromNullable(principalDetails.get(username));
//     }
// 
// }
// 
// Path: src/main/java/com/thoughtworks/go/strongauth/util/InputStreamSource.java
// public interface InputStreamSource {
// 
//     void addChangeListener(SourceChangeListener sourceChangeListener);
// 
//     InputStream inputStream() throws IOException;
// }
// 
// Path: src/main/java/com/thoughtworks/go/strongauth/util/io/SourceChangeListener.java
// public interface SourceChangeListener {
//     void sourceChanged(final SourceChangeEvent event);
// }


import com.google.common.base.Optional;
import com.thoughtworks.go.strongauth.authentication.principalDetailSources.ConfigurableUserPrincipalDetailSource;
import com.thoughtworks.go.strongauth.util.InputStreamSource;
import com.thoughtworks.go.strongauth.util.io.SourceChangeListener;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import java.io.InputStream;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
package com.thoughtworks.go.strongauth.authentication;




public class ConfigurableUserPrincipalDetailSourceTest {

    @Test
    public void testFindExistingUser() {
        InputStream passwordFile = IOUtils.toInputStream("username1:hazsh:salty:PBKDF2WithHmacSHA1(5000, 64)");
        PrincipalDetailSource principalDetailSource = new ConfigurableUserPrincipalDetailSource(new BasicInputStreamSource(passwordFile));
        Optional<PrincipalDetail> maybePrincipalDetail = principalDetailSource.byUsername("username1");
        assertThat(maybePrincipalDetail, is(Optional.of(
                new PrincipalDetail("username1", "hazsh", "salty", "PBKDF2WithHmacSHA1(5000, 64)"))));
    }

    @Test
    public void testFindExistingUserWithNotSalt() {
        InputStream passwordFile = IOUtils.toInputStream("username1:hazsh::PBKDF2WithHmacSHA1(5000, 64)");
        PrincipalDetailSource principalDetailSource = new ConfigurableUserPrincipalDetailSource(new BasicInputStreamSource(passwordFile));
        Optional<PrincipalDetail> maybePrincipalDetail = principalDetailSource.byUsername("username1");
        assertThat(maybePrincipalDetail, is(Optional.of(
                new PrincipalDetail("username1", "hazsh", "", "PBKDF2WithHmacSHA1(5000, 64)"))));
    }

    @Test
    public void testFindMissingUser() {
        InputStream passwordFile = IOUtils.toInputStream("username1:hazsh:salty:PBKDF2WithHmacSHA1(5000, 64)");
// Path: src/main/java/com/thoughtworks/go/strongauth/authentication/principalDetailSources/ConfigurableUserPrincipalDetailSource.java
// public class ConfigurableUserPrincipalDetailSource implements PrincipalDetailSource {
//     private final Map<String, PrincipalDetail> principalDetails = new HashMap<>();
//     public static final Pattern DETAIL_PATTERN = Pattern.compile("^([^:]+):([^:]+):([^:]*):([^:]+)$");
// 
//     private static final Logger LOGGER = Logger.getLoggerFor(ConfigurableUserPrincipalDetailSource.class);
//     public final String pluginId = Constants.PLUGIN_ID;
// 
//     public ConfigurableUserPrincipalDetailSource(InputStreamSource passwordSource) {
//         try {
//             loadSource(passwordSource.inputStream());
//         } catch (IOException e) {
//             LOGGER.warn("Missing password file. No credentials loaded.");
//         }
// 
//         passwordSource.addChangeListener(new SourceChangeListener() {
//             @Override
//             public void sourceChanged(SourceChangeEvent event) {
//                 try {
//                     loadSource(event.getInputStream());
//                 } catch (IOException e) {
//                     LOGGER.error("Missing password file. No credentials loaded.");
//                 }
//             }
//         });
//     }
// 
//     private void loadSource(InputStream passwordFile) throws IOException {
//         principalDetails.clear();
//         String line;
//         final BufferedReader bufferedReader = toBufferedReader(new InputStreamReader(passwordFile));
//         while ((line = bufferedReader.readLine()) != null) {
//             Optional<PrincipalDetail> maybeDetail = parse(line);
//             if (maybeDetail.isPresent()) {
//                 PrincipalDetail detail = maybeDetail.get();
//                 principalDetails.put(detail.getUsername(), detail);
//             }
//         }
//     }
// 
//     private Optional<PrincipalDetail> parse(final String line) {
//         final Matcher matcher = DETAIL_PATTERN.matcher(line);
//         if (matcher.find()) {
//             return Optional.of(new PrincipalDetail(
//                     matcher.group(1),
//                     matcher.group(2),
//                     matcher.group(3),
//                     matcher.group(4))
//             );
//         } else {
//             LOGGER.warn(format("Failed to parse password file line %s", line));
//             return Optional.absent();
//         }
//     }
// 
//     @Override
//     public Optional<PrincipalDetail> byUsername(String username) {
//         return Optional.fromNullable(principalDetails.get(username));
//     }
// 
// }
// 
// Path: src/main/java/com/thoughtworks/go/strongauth/util/InputStreamSource.java
// public interface InputStreamSource {
// 
//     void addChangeListener(SourceChangeListener sourceChangeListener);
// 
//     InputStream inputStream() throws IOException;
// }
// 
// Path: src/main/java/com/thoughtworks/go/strongauth/util/io/SourceChangeListener.java
// public interface SourceChangeListener {
//     void sourceChanged(final SourceChangeEvent event);
// }


// Path: src/test/java/com/thoughtworks/go/strongauth/authentication/ConfigurableUserPrincipalDetailSourceTest.java
import com.google.common.base.Optional;
import com.thoughtworks.go.strongauth.authentication.principalDetailSources.ConfigurableUserPrincipalDetailSource;
import com.thoughtworks.go.strongauth.util.InputStreamSource;
import com.thoughtworks.go.strongauth.util.io.SourceChangeListener;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import java.io.InputStream;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

package com.thoughtworks.go.strongauth.authentication;




public class ConfigurableUserPrincipalDetailSourceTest {

    @Test
    public void testFindExistingUser() {
        InputStream passwordFile = IOUtils.toInputStream("username1:hazsh:salty:PBKDF2WithHmacSHA1(5000, 64)");
        PrincipalDetailSource principalDetailSource = new ConfigurableUserPrincipalDetailSource(new BasicInputStreamSource(passwordFile));
        Optional<PrincipalDetail> maybePrincipalDetail = principalDetailSource.byUsername("username1");
        assertThat(maybePrincipalDetail, is(Optional.of(
                new PrincipalDetail("username1", "hazsh", "salty", "PBKDF2WithHmacSHA1(5000, 64)"))));
    }

    @Test
    public void testFindExistingUserWithNotSalt() {
        InputStream passwordFile = IOUtils.toInputStream("username1:hazsh::PBKDF2WithHmacSHA1(5000, 64)");
        PrincipalDetailSource principalDetailSource = new ConfigurableUserPrincipalDetailSource(new BasicInputStreamSource(passwordFile));
        Optional<PrincipalDetail> maybePrincipalDetail = principalDetailSource.byUsername("username1");
        assertThat(maybePrincipalDetail, is(Optional.of(
                new PrincipalDetail("username1", "hazsh", "", "PBKDF2WithHmacSHA1(5000, 64)"))));
    }

    @Test
    public void testFindMissingUser() {
        InputStream passwordFile = IOUtils.toInputStream("username1:hazsh:salty:PBKDF2WithHmacSHA1(5000, 64)");
        PrincipalDetailSource principalDetailSource = new ConfigurableUserPrincipalDetailSource(new BasicInputStreamSource(passwordFile));