// Path: src/main/java/com/statemachinesystems/envy/ConfigSource.java
// public interface ConfigSource {
// 
//     /**
//      * Retrieves the configuration value associated with the given parameter.
//      *
//      * @param parameter  the parameter to retrieve.
//      * @return           the value associated with the parameter, or null if no value was present
//      */
//     String getValue(Parameter parameter);
// }
// 
// Path: src/test/java/com/statemachinesystems/envy/common/FeatureTest.java
// public abstract class FeatureTest {
// 
//     protected Envy envy() {
//         return envy(valueParserFactory(), configSource());
//     }
// 
//     protected Envy envy(ValueParserFactory valueParserFactory) {
//         return envy(valueParserFactory, configSource());
//     }
// 
//     protected Envy envy(ConfigSource configSource) {
//         return envy(valueParserFactory(), configSource);
//     }
// 
//     protected Envy envy(ValueParserFactory valueParserFactory, ConfigSource configSource) {
//         return new Envy(valueParserFactory, configSource);
//     }
// 
//     protected ValueParserFactory valueParserFactory() {
//         List<ValueParser<?>> valueParsers = new ArrayList<ValueParser<?>>(Envy.defaultValueParsers());
//         return new ValueParserFactory(valueParsers);
//     }
// 
//     protected StubConfigSource configSource() {
//         return new StubConfigSource();
//     }
// }
// 
// Path: src/main/java/com/statemachinesystems/envy/values/SensitiveValue.java
// public class SensitiveValue<T> extends ResolvedValue<T> {
// 
//     public static final String MASKED_VALUE = "******";
// 
//     protected SensitiveValue(T value, Status status) {
//         super(value, status);
//     }
// 
//     @Override
//     public String format(Object proxy) {
//         return getStatus() == Status.MISSING
//                 ? super.format(proxy)
//                 : MASKED_VALUE;
//     }
// }


import com.statemachinesystems.envy.ConfigSource;
import com.statemachinesystems.envy.Nullable;
import com.statemachinesystems.envy.Sensitive;
import com.statemachinesystems.envy.common.FeatureTest;
import com.statemachinesystems.envy.values.SensitiveValue;
import org.junit.Test;
import java.util.Optional;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;
        @Sensitive
        Credentials credentials();
    }

    interface OptionalSensitive {
        @Sensitive
        Optional<Integer> secretNumber();
    }

    interface NestedOptional {
        @Sensitive
        Optional<Credentials> credentials();
    }

    interface Sub1 extends Credentials {
        String type();
    }

    interface Sub2 extends Credentials {
        @Override
        String password();
    }

    @Test
    public void masksSensitiveValues() {
        ConfigSource configSource = configSource()
                .add("username", "scott")
                .add("password", "tiger");
        Credentials config = envy(configSource).proxy(Credentials.class);
        assertThat(config.toString(), not(containsString("tiger")));
// Path: src/main/java/com/statemachinesystems/envy/ConfigSource.java
// public interface ConfigSource {
// 
//     /**
//      * Retrieves the configuration value associated with the given parameter.
//      *
//      * @param parameter  the parameter to retrieve.
//      * @return           the value associated with the parameter, or null if no value was present
//      */
//     String getValue(Parameter parameter);
// }
// 
// Path: src/test/java/com/statemachinesystems/envy/common/FeatureTest.java
// public abstract class FeatureTest {
// 
//     protected Envy envy() {
//         return envy(valueParserFactory(), configSource());
//     }
// 
//     protected Envy envy(ValueParserFactory valueParserFactory) {
//         return envy(valueParserFactory, configSource());
//     }
// 
//     protected Envy envy(ConfigSource configSource) {
//         return envy(valueParserFactory(), configSource);
//     }
// 
//     protected Envy envy(ValueParserFactory valueParserFactory, ConfigSource configSource) {
//         return new Envy(valueParserFactory, configSource);
//     }
// 
//     protected ValueParserFactory valueParserFactory() {
//         List<ValueParser<?>> valueParsers = new ArrayList<ValueParser<?>>(Envy.defaultValueParsers());
//         return new ValueParserFactory(valueParsers);
//     }
// 
//     protected StubConfigSource configSource() {
//         return new StubConfigSource();
//     }
// }
// 
// Path: src/main/java/com/statemachinesystems/envy/values/SensitiveValue.java
// public class SensitiveValue<T> extends ResolvedValue<T> {
// 
//     public static final String MASKED_VALUE = "******";
// 
//     protected SensitiveValue(T value, Status status) {
//         super(value, status);
//     }
// 
//     @Override
//     public String format(Object proxy) {
//         return getStatus() == Status.MISSING
//                 ? super.format(proxy)
//                 : MASKED_VALUE;
//     }
// }


// Path: src/test/java/com/statemachinesystems/envy/features/SensitiveValuesTest.java
import com.statemachinesystems.envy.ConfigSource;
import com.statemachinesystems.envy.Nullable;
import com.statemachinesystems.envy.Sensitive;
import com.statemachinesystems.envy.common.FeatureTest;
import com.statemachinesystems.envy.values.SensitiveValue;
import org.junit.Test;
import java.util.Optional;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;

        @Sensitive
        Credentials credentials();
    }

    interface OptionalSensitive {
        @Sensitive
        Optional<Integer> secretNumber();
    }

    interface NestedOptional {
        @Sensitive
        Optional<Credentials> credentials();
    }

    interface Sub1 extends Credentials {
        String type();
    }

    interface Sub2 extends Credentials {
        @Override
        String password();
    }

    @Test
    public void masksSensitiveValues() {
        ConfigSource configSource = configSource()
                .add("username", "scott")
                .add("password", "tiger");
        Credentials config = envy(configSource).proxy(Credentials.class);
        assertThat(config.toString(), not(containsString("tiger")));
        assertThat(config.toString(), containsString(SensitiveValue.MASKED_VALUE));