Home | History | Annotate | Download | only in config
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.android.tradefed.config;
     17 
     18 import com.android.tradefed.config.Option.Importance;
     19 import com.android.tradefed.util.keystore.IKeyStoreClient;
     20 import com.android.tradefed.util.keystore.StubKeyStoreClient;
     21 
     22 import junit.framework.TestCase;
     23 
     24 import org.easymock.EasyMock;
     25 
     26 import java.util.ArrayList;
     27 import java.util.Collection;
     28 import java.util.HashMap;
     29 import java.util.List;
     30 import java.util.Map;
     31 
     32 /**
     33  * Unit tests for {@link ArgsOptionParser}.
     34  */
     35 @SuppressWarnings("unused")
     36 public class ArgsOptionParserTest extends TestCase {
     37 
     38     /**
     39      * An option source with one {@link Option} specified.
     40      */
     41     private static class OneOptionSource {
     42 
     43         private static final String DEFAULT_VALUE = "default";
     44         private static final String OPTION_NAME = "my_option";
     45         private static final String OPTION_DESC = "option description";
     46 
     47         @Option(name=OPTION_NAME, shortName='o', description=OPTION_DESC)
     48         private String mMyOption = DEFAULT_VALUE;
     49     }
     50 
     51     /**
     52      * An option source with one {@link Option} specified.
     53      */
     54     private static class MapOptionSource {
     55 
     56         private static final String OPTION_NAME = "my_option";
     57         private static final String OPTION_DESC = "option description";
     58 
     59         @Option(name=OPTION_NAME, shortName='o', description=OPTION_DESC)
     60         private Map<Integer, Boolean> mMyOption = new HashMap<Integer, Boolean>();
     61     }
     62 
     63     /**
     64      * An option source with one {@link Option} specified.
     65      */
     66     private static class MapStringOptionSource {
     67 
     68         private static final String OPTION_NAME = "my_option";
     69         private static final String OPTION_DESC = "option description";
     70 
     71         @Option(name=OPTION_NAME, shortName='o', description=OPTION_DESC)
     72         private Map<String, String> mMyOption = new HashMap<String, String>();
     73     }
     74 
     75     /**
     76      * An option source with boolean {@link Option} specified.
     77      */
     78     private static class BooleanOptionSource {
     79 
     80         private static final boolean DEFAULT_BOOL = false;
     81         private static final String DEFAULT_VALUE = "default";
     82 
     83         @Option(name="my_boolean", shortName='b')
     84         private boolean mMyBool = DEFAULT_BOOL;
     85 
     86         @Option(name="my_option", shortName='o')
     87         protected String mMyOption = DEFAULT_VALUE;
     88     }
     89 
     90     /**
     91      * An option source with boolean {@link Option} specified with default = true.
     92      */
     93     private static class BooleanTrueOptionSource {
     94 
     95         private static final boolean DEFAULT_BOOL = true;
     96 
     97         @Option(name="my_boolean", shortName='b')
     98         private boolean mMyBool = DEFAULT_BOOL;
     99     }
    100 
    101     /**
    102      * An option source that has a superclass with options
    103      */
    104     private static class InheritedOptionSource extends OneOptionSource {
    105 
    106         private static final String OPTION_NAME = "my_sub_option";
    107         private static final String OPTION_DESC = "sub description";
    108 
    109         @Option(name=OPTION_NAME, description=OPTION_DESC)
    110         private String mMySubOption = "";
    111     }
    112 
    113     /**
    114      * An option source for testing the {@link Option#importance()} settings
    115      */
    116     private static class ImportantOptionSource {
    117 
    118         private static final String IMPORTANT_OPTION_NAME = "important_option";
    119         private static final String IMPORTANT_UNSET_OPTION_NAME = "unset_important_option";
    120         private static final String UNIMPORTANT_OPTION_NAME = "unimportant_option";
    121 
    122         @Option(name = IMPORTANT_OPTION_NAME, description = IMPORTANT_OPTION_NAME,
    123                 importance = Importance.ALWAYS)
    124         private String mImportantOption = "foo";
    125 
    126         @Option(name = IMPORTANT_UNSET_OPTION_NAME, description = IMPORTANT_UNSET_OPTION_NAME,
    127                 importance = Importance.IF_UNSET)
    128         private String mImportantUnsetOption = null;
    129 
    130         @Option(name = UNIMPORTANT_OPTION_NAME, description = UNIMPORTANT_OPTION_NAME,
    131                 importance = Importance.NEVER)
    132         private String mUnimportantOption = null;
    133 
    134         ImportantOptionSource(String setOption) {
    135             mImportantUnsetOption = setOption;
    136         }
    137 
    138         ImportantOptionSource() {
    139         }
    140     }
    141 
    142     /**
    143      * Option source whose options shouldn't end up in the global namespace
    144      */
    145     @OptionClass(alias = "ngos", global_namespace = false)
    146     private static class NonGlobalOptionSource {
    147         @Option(name = "option")
    148         Boolean mOption = null;
    149     }
    150 
    151     /**
    152      * Option source with mandatory options
    153      */
    154     private static class MandatoryOptionSourceNoDefault {
    155         @Option(name = "no-default", mandatory = true)
    156         private String mNoDefaultOption;
    157     }
    158 
    159     /**
    160      * Option source with mandatory options
    161      */
    162     private static class MandatoryOptionSourceNull {
    163         @Option(name = "null", mandatory = true)
    164         private String mNullOption = null;
    165     }
    166 
    167     /**
    168      * Option source with mandatory options
    169      */
    170     private static class MandatoryOptionSourceEmptyCollection {
    171         @Option(name = "empty-collection", mandatory = true)
    172         private Collection<String> mEmptyCollection = new ArrayList<String>(0);
    173     }
    174 
    175     /**
    176      * Option source with mandatory options
    177      */
    178     private static class MandatoryOptionSourceEmptyMap {
    179         @Option(name = "empty-map", mandatory = true)
    180         private Map<String, String> mEmptyMap = new HashMap<String, String>();
    181     }
    182 
    183     /**
    184      * An option source that exercises the {@link OptionUpdateRule}s.
    185      */
    186     private static class OptionUpdateRuleSource {
    187 
    188         public static final String DEFAULT_VALUE = "5 default";
    189         public static final String BIGGER_VALUE = "9 bigger";
    190         public static final String SMALLER_VALUE = "0 smaller";
    191 
    192         @Option(name = "default")
    193         private String mDefaultOption = DEFAULT_VALUE;
    194 
    195         @Option(name = "first", updateRule = OptionUpdateRule.FIRST)
    196         private String mFirstOption = DEFAULT_VALUE;
    197 
    198         @Option(name = "last", updateRule = OptionUpdateRule.LAST)
    199         private String mLastOption = DEFAULT_VALUE;
    200 
    201         @Option(name = "greatest", updateRule = OptionUpdateRule.GREATEST)
    202         private String mGreatestOption = DEFAULT_VALUE;
    203 
    204         @Option(name = "least", updateRule = OptionUpdateRule.LEAST)
    205         private String mLeastOption = DEFAULT_VALUE;
    206 
    207         @Option(name = "immutable", updateRule = OptionUpdateRule.IMMUTABLE)
    208         private String mImmutableOption = DEFAULT_VALUE;
    209 
    210         @Option(name = "null-immutable", updateRule = OptionUpdateRule.IMMUTABLE)
    211         private String mNullImmutableOption = null;
    212     }
    213 
    214 
    215     // SECTION: option update rule validation
    216     /**
    217      * Verify that {@link OptionUpdateRule}s work properly when the update compares to greater-than
    218      * the default value.
    219      */
    220     public void testOptionUpdateRule_greater() throws Exception {
    221         OptionUpdateRuleSource object = new OptionUpdateRuleSource();
    222         ArgsOptionParser parser = new ArgsOptionParser(object);
    223         final String current = OptionUpdateRuleSource.DEFAULT_VALUE;
    224         final String big = OptionUpdateRuleSource.BIGGER_VALUE;
    225 
    226         parser.parse(new String[] {"--default", big, "--first", big, "--last", big,
    227                 "--greatest", big, "--least", big});
    228         assertEquals(current, object.mFirstOption);
    229         assertEquals(big, object.mLastOption);
    230         assertEquals(big, object.mDefaultOption);  // default should be LAST
    231         assertEquals(big, object.mGreatestOption);
    232         assertEquals(current, object.mLeastOption);
    233     }
    234 
    235     /**
    236      * Verify that {@link OptionUpdateRule}s work properly when the update compares to greater-than
    237      * the default value.
    238      */
    239     public void testOptionUpdateRule_lesser() throws Exception {
    240         OptionUpdateRuleSource object = new OptionUpdateRuleSource();
    241         ArgsOptionParser parser = new ArgsOptionParser(object);
    242         final String current = OptionUpdateRuleSource.DEFAULT_VALUE;
    243         final String small = OptionUpdateRuleSource.SMALLER_VALUE;
    244 
    245         parser.parse(new String[] {"--default", small, "--first", small, "--last", small,
    246                 "--greatest", small, "--least", small});
    247         assertEquals(current, object.mFirstOption);
    248         assertEquals(small, object.mLastOption);
    249         assertEquals(small, object.mDefaultOption);  // default should be LAST
    250         assertEquals(current, object.mGreatestOption);
    251         assertEquals(small, object.mLeastOption);
    252     }
    253 
    254     /**
    255      * Verify that {@link OptionUpdateRule}s work properly when the update compares to greater-than
    256      * the default value.
    257      */
    258     public void testOptionUpdateRule_immutable() throws Exception {
    259         OptionUpdateRuleSource object = new OptionUpdateRuleSource();
    260         ArgsOptionParser parser = new ArgsOptionParser(object);
    261         final String update = OptionUpdateRuleSource.BIGGER_VALUE;
    262 
    263         try {
    264             parser.parse(new String[] {"--immutable", update});
    265             fail("ConfigurationException not thrown when updating an IMMUTABLE option");
    266         } catch (ConfigurationException e) {
    267             // expected
    268         }
    269 
    270         assertNull(object.mNullImmutableOption);
    271         parser.parse(new String[] {"--null-immutable", update});
    272         assertEquals(update, object.mNullImmutableOption);
    273 
    274         try {
    275             parser.parse(new String[] {"--null-immutable", update});
    276             fail("ConfigurationException not thrown when updating an IMMUTABLE option");
    277         } catch (ConfigurationException e) {
    278             // expected
    279         }
    280     }
    281 
    282     /**
    283      * Setting an option with a namespace alias should work fine
    284      */
    285     public void testNonGlobalOptionSource_alias() throws Exception {
    286         NonGlobalOptionSource source = new NonGlobalOptionSource();
    287         ArgsOptionParser parser = new ArgsOptionParser(source);
    288 
    289         assertNull(source.mOption);
    290         parser.parse(new String[] {"--ngos:option"});
    291         assertTrue(source.mOption);
    292         parser.parse(new String[] {"--ngos:no-option"});
    293         assertFalse(source.mOption);
    294     }
    295 
    296     /**
    297      * Setting an option with a classname namespace should work fine
    298      */
    299     public void testNonGlobalOptionSource_className() throws Exception {
    300         NonGlobalOptionSource source = new NonGlobalOptionSource();
    301         ArgsOptionParser parser = new ArgsOptionParser(source);
    302 
    303         assertNull(source.mOption);
    304         parser.parse(new String[] {String.format("--%s:option", source.getClass().getName())});
    305         assertTrue(source.mOption);
    306         parser.parse(new String[] {String.format("--%s:no-option", source.getClass().getName())});
    307         assertFalse(source.mOption);
    308     }
    309 
    310     /**
    311      * Setting an option without a namespace should fail
    312      */
    313     public void testNonGlobalOptionSource_global() throws Exception {
    314         NonGlobalOptionSource source = new NonGlobalOptionSource();
    315         ArgsOptionParser parser = new ArgsOptionParser(source);
    316 
    317         assertNull(source.mOption);
    318         try {
    319             parser.parse(new String[] {"--option"});
    320             fail("ConfigurationException not thrown when assigning a global option to an @Option " +
    321                     "field in a non-global-namespace class");
    322         } catch (ConfigurationException e) {
    323             // expected
    324         }
    325 
    326         try {
    327             parser.parse(new String[] {"--no-option"});
    328             fail("ConfigurationException not thrown when assigning a global option to an @Option " +
    329                     "field in a non-global-namespace class");
    330         } catch (ConfigurationException e) {
    331             // expected
    332         }
    333     }
    334 
    335 
    336     // SECTION: tests for #parse(...)
    337     /**
    338     * Test passing an empty argument list for an object that has one option specified.
    339     * <p/>
    340     * Expected that the option field should retain its default value.
    341     */
    342     public void testParse_noArg() throws ConfigurationException {
    343         OneOptionSource object = new OneOptionSource();
    344         ArgsOptionParser parser = new ArgsOptionParser(object);
    345         parser.parse(new String[] {});
    346         assertEquals(OneOptionSource.DEFAULT_VALUE, object.mMyOption);
    347     }
    348 
    349     /**
    350      * Test passing an single argument for an object that has one option specified.
    351      */
    352     public void testParse_oneArg() throws ConfigurationException {
    353         OneOptionSource object = new OneOptionSource();
    354         ArgsOptionParser parser = new ArgsOptionParser(object);
    355         final String expectedValue = "set";
    356         parser.parse(new String[] {"--my_option", expectedValue});
    357         assertEquals(expectedValue, object.mMyOption);
    358     }
    359 
    360     /**
    361      * Test passing an single argument for an object that has one option specified.
    362      */
    363     public void testParse_oneMapArg() throws ConfigurationException {
    364         MapOptionSource object = new MapOptionSource();
    365         ArgsOptionParser parser = new ArgsOptionParser(object);
    366         final int expectedKey = 13;
    367         final boolean expectedValue = true;
    368         parser.parse(new String[] {"--my_option", Integer.toString(expectedKey),
    369                 Boolean.toString(expectedValue)});
    370         assertNotNull(object.mMyOption);
    371         assertEquals(1, object.mMyOption.size());
    372         assertEquals(expectedValue, (boolean) object.mMyOption.get(expectedKey));
    373     }
    374 
    375     /**
    376      * Test passing an single argument for an object that has one option specified.
    377      */
    378     public void testParseMapArg_mismatchKeyType() throws ConfigurationException {
    379         MapOptionSource object = new MapOptionSource();
    380         ArgsOptionParser parser = new ArgsOptionParser(object);
    381         final String expectedKey = "istanbul";
    382         final boolean expectedValue = true;
    383         try {
    384             parser.parse(new String[] {"--my_option", expectedKey, Boolean.toString(expectedValue)});
    385             fail("ConfigurationException not thrown");
    386         } catch (ConfigurationException e) {
    387             // expect an exception that explicitly mentions that the "key" is incorrect
    388             assertTrue(String.format("Expected exception message to contain 'key': %s",
    389                     e.getMessage()), e.getMessage().contains("key"));
    390             assertTrue(String.format("Expected exception message to contain '%s': %s",
    391                     expectedKey, e.getMessage()), e.getMessage().contains(expectedKey));
    392         }
    393     }
    394 
    395     /**
    396      * Test passing an single argument for an object that has one option specified.
    397      */
    398     public void testParseMapArg_mismatchValueType() throws ConfigurationException {
    399         MapOptionSource object = new MapOptionSource();
    400         ArgsOptionParser parser = new ArgsOptionParser(object);
    401         final int expectedKey = 13;
    402         final String expectedValue = "notconstantinople";
    403         try {
    404             parser.parse(new String[] {"--my_option", Integer.toString(expectedKey), expectedValue});
    405             fail("ConfigurationException not thrown");
    406         } catch (ConfigurationException e) {
    407             // expect an exception that explicitly mentions that the "value" is incorrect
    408             assertTrue(String.format("Expected exception message to contain 'value': '%s'",
    409                     e.getMessage()), e.getMessage().contains("value"));
    410             assertTrue(String.format("Expected exception message to contain '%s': %s",
    411                     expectedValue, e.getMessage()), e.getMessage().contains(expectedValue));
    412         }
    413     }
    414 
    415     /**
    416      * Test passing an single argument for an object that has one option specified.
    417      */
    418     public void testParseMapArg_missingKey() throws ConfigurationException {
    419         MapOptionSource object = new MapOptionSource();
    420         ArgsOptionParser parser = new ArgsOptionParser(object);
    421         try {
    422             parser.parse(new String[] {"--my_option"});
    423             fail("ConfigurationException not thrown");
    424         } catch (ConfigurationException e) {
    425             // expect an exception that explicitly mentions that the "key" is incorrect
    426             assertTrue(String.format("Expected exception message to contain 'key': '%s'",
    427                     e.getMessage()), e.getMessage().contains("key"));
    428         }
    429     }
    430 
    431     /**
    432      * Test passing an single argument for an object that has one option specified.
    433      */
    434     public void testParseMapArg_missingValue() throws ConfigurationException {
    435         MapOptionSource object = new MapOptionSource();
    436         ArgsOptionParser parser = new ArgsOptionParser(object);
    437         final int expectedKey = 13;
    438         try {
    439             parser.parse(new String[] {"--my_option", Integer.toString(expectedKey)});
    440             fail("ConfigurationException not thrown");
    441         } catch (ConfigurationException e) {
    442             // expect an exception that explicitly mentions that the "value" is incorrect
    443             assertTrue(String.format("Expected exception message to contain 'value': '%s'",
    444                     e.getMessage()), e.getMessage().contains("value"));
    445         }
    446     }
    447 
    448     /**
    449      * Test passing an single argument for an object that has one option specified, using the
    450      * option=value notation.
    451      */
    452     public void testParse_oneArgEquals() throws ConfigurationException {
    453         OneOptionSource object = new OneOptionSource();
    454         ArgsOptionParser parser = new ArgsOptionParser(object);
    455         final String expectedValue = "set";
    456         parser.parse(new String[] {String.format("--my_option=%s", expectedValue)});
    457         assertEquals(expectedValue, object.mMyOption);
    458     }
    459 
    460     /**
    461      * Test passing a single argument for an object that has one option specified, using the
    462      * short option notation.
    463      */
    464     public void testParse_oneShortArg() throws ConfigurationException {
    465         OneOptionSource object = new OneOptionSource();
    466         ArgsOptionParser parser = new ArgsOptionParser(object);
    467         final String expectedValue = "set";
    468         parser.parse(new String[] {"-o", expectedValue});
    469         assertEquals(expectedValue, object.mMyOption);
    470     }
    471 
    472     /**
    473      * Test that "--" marks the beginning of positional arguments
    474      */
    475     public void testParse_posArgs() throws ConfigurationException {
    476         OneOptionSource object = new OneOptionSource();
    477         ArgsOptionParser parser = new ArgsOptionParser(object);
    478         final String expectedValue = "set";
    479         // have a position argument with a long option prefix, to try to confuse the parser
    480         final String posArg = "--unused";
    481         List<String> leftOver = parser.parse(new String[] {"-o", expectedValue, "--", posArg});
    482         assertEquals(expectedValue, object.mMyOption);
    483         assertTrue(leftOver.contains(posArg));
    484     }
    485 
    486     /**
    487      * Test passing a single boolean argument.
    488      */
    489     public void testParse_boolArg() throws ConfigurationException {
    490         BooleanOptionSource object = new BooleanOptionSource();
    491         ArgsOptionParser parser = new ArgsOptionParser(object);
    492         parser.parse(new String[] {"-b"});
    493         assertTrue(object.mMyBool);
    494     }
    495 
    496     /**
    497      * Test passing a boolean argument with another short argument.
    498      */
    499     public void testParse_boolTwoArg() throws ConfigurationException {
    500         BooleanOptionSource object = new BooleanOptionSource();
    501         ArgsOptionParser parser = new ArgsOptionParser(object);
    502         final String expectedValue = "set";
    503         parser.parse(new String[] {"-bo", expectedValue});
    504         assertTrue(object.mMyBool);
    505         assertEquals(expectedValue, object.mMyOption);
    506     }
    507 
    508     /**
    509      * Test passing a boolean argument with another short argument, with value concatenated.
    510      * e.g -bovalue
    511      */
    512     public void testParse_boolTwoArgValue() throws ConfigurationException {
    513         BooleanOptionSource object = new BooleanOptionSource();
    514         ArgsOptionParser parser = new ArgsOptionParser(object);
    515         final String expectedValue = "set";
    516         parser.parse(new String[] {String.format("-bo%s", expectedValue)});
    517         assertTrue(object.mMyBool);
    518         assertEquals(expectedValue, object.mMyOption);
    519     }
    520 
    521     /**
    522      * Test the "--no-(bool option)" syntax
    523      */
    524     public void testParse_boolFalse() throws ConfigurationException {
    525         BooleanTrueOptionSource object = new BooleanTrueOptionSource();
    526         ArgsOptionParser parser = new ArgsOptionParser(object);
    527         parser.parse(new String[] {"--no-my_boolean"});
    528         assertFalse(object.mMyBool);
    529     }
    530 
    531     /**
    532      * Test the boolean long option syntax
    533      */
    534     public void testParse_boolLong() throws ConfigurationException {
    535         BooleanOptionSource object = new BooleanOptionSource();
    536         ArgsOptionParser parser = new ArgsOptionParser(object);
    537         parser.parse(new String[] {"--my_boolean"});
    538         assertTrue(object.mMyBool);
    539     }
    540 
    541     /**
    542      * Test passing arg string where value is missing
    543      */
    544     public void testParse_missingValue() throws ConfigurationException {
    545         OneOptionSource object = new OneOptionSource();
    546         ArgsOptionParser parser = new ArgsOptionParser(object);
    547         try {
    548             parser.parse(new String[] {"--my_option"});
    549             fail("ConfigurationException not thrown");
    550         } catch (ConfigurationException e) {
    551             // expected
    552         }
    553     }
    554 
    555     /**
    556      * Test parsing args for an option that does not exist.
    557      */
    558     public void testParse_optionNotPresent() throws ConfigurationException {
    559         OneOptionSource object = new OneOptionSource();
    560         ArgsOptionParser parser = new ArgsOptionParser(object);
    561         try {
    562             parser.parse(new String[] {"--my_option", "set", "--not_here", "value"});
    563             fail("ConfigurationException not thrown");
    564         } catch (ConfigurationException e) {
    565             // expected
    566         }
    567     }
    568 
    569 
    570     // SECTION: tests for #parseBestEffort(...)
    571     /**
    572      * Test passing an single argument for an object that has one option specified.
    573      */
    574     public void testParseBestEffort_oneArg() throws ConfigurationException {
    575         OneOptionSource object = new OneOptionSource();
    576         ArgsOptionParser parser = new ArgsOptionParser(object);
    577         final String option = "--my_option";
    578         final String value = "set";
    579         final List<String> leftovers = parser.parseBestEffort(
    580                 new String[] {option, value});
    581         assertEquals(value, object.mMyOption);
    582         assertEquals(0, leftovers.size());
    583     }
    584 
    585     /**
    586      * Make sure that overwriting arguments works as expected.
    587      */
    588     public void testParseBestEffort_oneArg_overwrite() throws ConfigurationException {
    589         OneOptionSource object = new OneOptionSource();
    590         ArgsOptionParser parser = new ArgsOptionParser(object);
    591         final String option = "--my_option";
    592         final String value1 = "set";
    593         final String value2 = "game";
    594         final List<String> leftovers = parser.parseBestEffort(
    595                 new String[] {option, value1, option, value2});
    596         assertEquals(value2, object.mMyOption);
    597         assertEquals(0, leftovers.size());
    598     }
    599 
    600     /**
    601      * Test passing a usable argument followed by an unusable one.
    602      */
    603     public void testParseBestEffort_oneArg_oneLeftover() throws ConfigurationException {
    604         OneOptionSource object = new OneOptionSource();
    605         ArgsOptionParser parser = new ArgsOptionParser(object);
    606         final String expectedValue = "set";
    607         final String leftoverOption = "--no_exist";
    608         final List<String> leftovers = parser.parseBestEffort(
    609                 new String[] {"--my_option", expectedValue, leftoverOption});
    610         assertEquals(expectedValue, object.mMyOption);
    611         assertEquals(1, leftovers.size());
    612         assertEquals(leftoverOption, leftovers.get(0));
    613     }
    614 
    615     /**
    616      * Test passing an unusable argument followed by a usable one.  Basically verifies that the
    617      * parse attempt stops wholesale, and doesn't merely skip the unusable arg.
    618      */
    619     public void testParseBestEffort_oneLeftover_oneArg() throws ConfigurationException {
    620         OneOptionSource object = new OneOptionSource();
    621         ArgsOptionParser parser = new ArgsOptionParser(object);
    622         final String goodOption = "--my_option";
    623         final String value = "set";
    624         final String badOption = "--no_exist";
    625         final List<String> leftovers = parser.parseBestEffort(
    626                 new String[] {badOption, goodOption, value});
    627         assertEquals(OneOptionSource.DEFAULT_VALUE, object.mMyOption);
    628         assertEquals(3, leftovers.size());
    629         assertEquals(badOption, leftovers.get(0));
    630         assertEquals(goodOption, leftovers.get(1));
    631         assertEquals(value, leftovers.get(2));
    632     }
    633 
    634     /**
    635      * Make sure that parsing stops when a bare option prefix, "--", is encountered.  That prefix
    636      * should _not_ be returned as one of the leftover args.
    637      */
    638     public void testParseBestEffort_manualStop() throws ConfigurationException {
    639         OneOptionSource object = new OneOptionSource();
    640         ArgsOptionParser parser = new ArgsOptionParser(object);
    641         final String goodOption = "--my_option";
    642         final String value = "set";
    643         final String badOption = "--no_exist";
    644         final List<String> leftovers = parser.parseBestEffort(
    645                 new String[] {"--", badOption, goodOption, value});
    646         assertEquals(OneOptionSource.DEFAULT_VALUE, object.mMyOption);
    647         assertEquals(3, leftovers.size());
    648         assertEquals(badOption, leftovers.get(0));
    649         assertEquals(goodOption, leftovers.get(1));
    650         assertEquals(value, leftovers.get(2));
    651     }
    652 
    653     /**
    654      * Make sure that parsing stops when a bare word is encountered.  Unlike a bare option prefix,
    655      * the bare word _should_ be returned as one of the leftover args.
    656      */
    657     public void testParseBestEffort_bareWord() throws ConfigurationException {
    658         OneOptionSource object = new OneOptionSource();
    659         ArgsOptionParser parser = new ArgsOptionParser(object);
    660         final String goodOption = "--my_option";
    661         final String value = "set";
    662         final String badOption = "--no_exist";
    663         final String bareWord = "configName";
    664         final List<String> leftovers = parser.parseBestEffort(
    665                 new String[] {bareWord, badOption, goodOption, value});
    666         assertEquals(OneOptionSource.DEFAULT_VALUE, object.mMyOption);
    667         assertEquals(4, leftovers.size());
    668         assertEquals(bareWord, leftovers.get(0));
    669         assertEquals(badOption, leftovers.get(1));
    670         assertEquals(goodOption, leftovers.get(2));
    671         assertEquals(value, leftovers.get(3));
    672     }
    673 
    674     /**
    675      * Make sure that parsing stops when a bare option prefix, "--", is encountered.  That prefix
    676      * should _not_ be returned as one of the leftover args.
    677      */
    678     public void testParseBestEffort_oneArg_manualStop() throws ConfigurationException {
    679         OneOptionSource object = new OneOptionSource();
    680         ArgsOptionParser parser = new ArgsOptionParser(object);
    681         final String option = "--my_option";
    682         final String value1 = "set";
    683         final String value2 = "game";
    684         final List<String> leftovers = parser.parseBestEffort(
    685                 new String[] {option, value1, "--", option, value2});
    686         assertEquals(value1, object.mMyOption);
    687         assertEquals(2, leftovers.size());
    688         assertEquals(option, leftovers.get(0));
    689         assertEquals(value2, leftovers.get(1));
    690     }
    691 
    692     /**
    693      * Make sure that parsing stops when a bare word is encountered.  Unlike a bare option prefix,
    694      * the bare word _should_ be returned as one of the leftover args.
    695      */
    696     public void testParseBestEffort_oneArg_bareWord() throws ConfigurationException {
    697         OneOptionSource object = new OneOptionSource();
    698         ArgsOptionParser parser = new ArgsOptionParser(object);
    699         final String option = "--my_option";
    700         final String value1 = "set";
    701         final String value2 = "game";
    702         final String bareWord = "configName";
    703         final List<String> leftovers = parser.parseBestEffort(
    704                 new String[] {option, value1, bareWord, option, value2});
    705         assertEquals(value1, object.mMyOption);
    706         assertEquals(3, leftovers.size());
    707         assertEquals(bareWord, leftovers.get(0));
    708         assertEquals(option, leftovers.get(1));
    709         assertEquals(value2, leftovers.get(2));
    710     }
    711 
    712     /**
    713      * Test passing an single argument for an object that has one option specified.
    714      */
    715     public void testParseBestEffort_oneArg_twoLeftovers() throws ConfigurationException {
    716         OneOptionSource object = new OneOptionSource();
    717         ArgsOptionParser parser = new ArgsOptionParser(object);
    718         final String expectedValue = "set";
    719         final String leftover1 = "--no_exist";
    720         final String leftover2 = "--me_neither";
    721         final List<String> leftovers = parser.parseBestEffort(
    722                 new String[] {"--my_option", expectedValue, leftover1, leftover2});
    723         assertEquals(expectedValue, object.mMyOption);
    724         assertEquals(2, leftovers.size());
    725         assertEquals(leftover1, leftovers.get(0));
    726         assertEquals(leftover2, leftovers.get(1));
    727     }
    728 
    729     /**
    730      * Make sure that map option parsing works as expected.
    731      */
    732     public void testParseBestEffort_mapOption() throws ConfigurationException {
    733         MapOptionSource object = new MapOptionSource();
    734         ArgsOptionParser parser = new ArgsOptionParser(object);
    735         final String option = "--my_option";
    736         final String key = "123";  // Integer is the key type
    737         final String value = "true";  // Boolean is the value type
    738         final String key2 = "345";  // Integer is the key type
    739         final String value2 = "false";  // Boolean is the value type
    740         final Integer expKey = 123;
    741         final Boolean expValue = Boolean.TRUE;
    742         final Integer expKey2 = 345;
    743         final Boolean expValue2 = Boolean.FALSE;
    744 
    745         final List<String> leftovers = parser.parseBestEffort(
    746                 new String[] {option, key, value, option, key2, value2});
    747 
    748         assertEquals(0, leftovers.size());
    749         assertNotNull(object.mMyOption);
    750         assertEquals(2, object.mMyOption.size());
    751         assertTrue(object.mMyOption.containsKey(expKey));
    752         assertEquals(expValue, object.mMyOption.get(expKey));
    753         assertTrue(object.mMyOption.containsKey(expKey2));
    754         assertEquals(expValue2, object.mMyOption.get(expKey2));
    755     }
    756 
    757     /**
    758      * Make sure that the single value map option parsing works as expected.
    759      */
    760     public void testParseBestEffort_mapOption_singleValue() throws ConfigurationException {
    761         MapOptionSource object = new MapOptionSource();
    762         ArgsOptionParser parser = new ArgsOptionParser(object);
    763         final String option = "--my_option";
    764         final String value = "123=true";  // Integer is the key type
    765         final Integer expKey = 123;
    766         final Boolean expValue = Boolean.TRUE;
    767 
    768         final List<String> leftovers = parser.parseBestEffort(
    769                 new String[] {option, value});
    770 
    771         assertEquals(0, leftovers.size());
    772         assertNotNull(object.mMyOption);
    773         assertEquals(1, object.mMyOption.size());
    774         assertTrue(object.mMyOption.containsKey(expKey));
    775         assertEquals(expValue, object.mMyOption.get(expKey));
    776     }
    777 
    778     /**
    779      * Make sure that the single map option parsing works as expected with escaped value.
    780      */
    781     public void testParseBestEffort_mapOption_escaping() throws ConfigurationException {
    782         MapStringOptionSource object = new MapStringOptionSource();
    783         ArgsOptionParser parser = new ArgsOptionParser(object);
    784         final String option = "--my_option";
    785         final String key = "hello\\=bar";
    786         final String value = "123\\=true";
    787         final String expKey = "hello=bar";
    788         final String expValue = "123=true";
    789 
    790         final List<String> leftovers = parser.parseBestEffort(
    791                 new String[] {option, key, value});
    792 
    793         assertEquals(0, leftovers.size());
    794         assertNotNull(object.mMyOption);
    795         assertEquals(1, object.mMyOption.size());
    796         assertTrue(object.mMyOption.containsKey(expKey));
    797         assertEquals(expValue, object.mMyOption.get(expKey));
    798     }
    799 
    800     /**
    801      * Make sure that the single map option parsing works as expected with escaped value.
    802      */
    803     public void testParseBestEffort_mapOption_singleValue_escaping() throws ConfigurationException {
    804         MapStringOptionSource object = new MapStringOptionSource();
    805         ArgsOptionParser parser = new ArgsOptionParser(object);
    806         final String option = "--my_option";
    807         final String value = "hello\\=bar=123\\=true\\=more";
    808         // Note that the actual value we store, is escaped.
    809         final String expKey = "hello=bar";
    810         final String expValue = "123=true=more";
    811 
    812         final List<String> leftovers = parser.parseBestEffort(
    813                 new String[] {option, value});
    814 
    815         assertEquals(0, leftovers.size());
    816         assertNotNull(object.mMyOption);
    817         assertEquals(1, object.mMyOption.size());
    818         assertTrue(object.mMyOption.containsKey(expKey));
    819         assertEquals(expValue, object.mMyOption.get(expKey));
    820     }
    821 
    822     /**
    823      * Make sure that the both map option parsing work together as expected.
    824      */
    825     public void testParseBestEffort_mapOption_bothFormat() throws ConfigurationException {
    826         MapOptionSource object = new MapOptionSource();
    827         ArgsOptionParser parser = new ArgsOptionParser(object);
    828         final String option = "--my_option";
    829         final String value = "123=true";  // Integer is the key type
    830         final String key2 = "234";
    831         final String value2 = "false";
    832         final Integer expKey = 123;
    833         final Boolean expValue = Boolean.TRUE;
    834         final Integer expKey2 = 234;
    835         final Boolean expValue2 = Boolean.FALSE;
    836 
    837         final List<String> leftovers = parser.parseBestEffort(
    838                 new String[] {option, value, option, key2, value2});
    839 
    840         assertEquals(0, leftovers.size());
    841         assertNotNull(object.mMyOption);
    842         assertEquals(2, object.mMyOption.size());
    843         assertTrue(object.mMyOption.containsKey(expKey));
    844         assertEquals(expValue, object.mMyOption.get(expKey));
    845         assertTrue(object.mMyOption.containsKey(expKey2));
    846         assertEquals(expValue2, object.mMyOption.get(expKey2));
    847     }
    848 
    849     /**
    850      * Make sure that we backtrack the appropriate amount when a Map option parse fails in the
    851      * middle
    852      */
    853     public void testParseBestEffort_mapOption_missingValue() throws ConfigurationException {
    854         MapOptionSource object = new MapOptionSource();
    855         ArgsOptionParser parser = new ArgsOptionParser(object);
    856         final String option = "--my_option";
    857         final String key = "123";  // Integer is the key type
    858         final List<String> leftovers = parser.parseBestEffort(
    859                 new String[] {option, key});
    860         assertTrue(object.mMyOption.isEmpty());
    861         assertEquals(2, leftovers.size());
    862         assertEquals(option, leftovers.get(0));
    863         assertEquals(key, leftovers.get(1));
    864     }
    865 
    866     /**
    867      * Make sure that we backtrack the appropriate amount when a Map option parse fails in the
    868      * middle
    869      */
    870     public void testParseBestEffort_mapOption_badValue() throws ConfigurationException {
    871         MapOptionSource object = new MapOptionSource();
    872         ArgsOptionParser parser = new ArgsOptionParser(object);
    873         final String option = "--my_option";
    874         final String key = "123";  // Integer is the key type
    875         final String value = "notBoolean";  // Boolean is the value type
    876         final List<String> leftovers = parser.parseBestEffort(
    877                 new String[] {option, key, value});
    878         assertTrue(object.mMyOption.isEmpty());
    879         assertEquals(3, leftovers.size());
    880         assertEquals(option, leftovers.get(0));
    881         assertEquals(key, leftovers.get(1));
    882         assertEquals(value, leftovers.get(2));
    883     }
    884 
    885     /**
    886      * Make sure that we backtrack the appropriate amount when a Map option parse fails in the
    887      * middle
    888      */
    889     public void testParseBestEffort_mapOption_badKey() throws ConfigurationException {
    890         MapOptionSource object = new MapOptionSource();
    891         ArgsOptionParser parser = new ArgsOptionParser(object);
    892         final String option = "--my_option";
    893         final String key = "NotANumber";  // Integer is the key type
    894         final String value = "true";  // Boolean is the value type
    895         final List<String> leftovers = parser.parseBestEffort(
    896                 new String[] {option, key, value});
    897         assertTrue(object.mMyOption.isEmpty());
    898         assertEquals(3, leftovers.size());
    899         assertEquals(option, leftovers.get(0));
    900         assertEquals(key, leftovers.get(1));
    901         assertEquals(value, leftovers.get(2));
    902     }
    903 
    904     /**
    905      * Make sure that the single key value for map works.
    906      */
    907     public void testParseBestEffort_mapOption_singleValue_badValue() throws ConfigurationException {
    908         MapOptionSource object = new MapOptionSource();
    909         ArgsOptionParser parser = new ArgsOptionParser(object);
    910         final String option = "--my_option";
    911         final String value = "too=many=equals";
    912         final List<String> leftovers = parser.parseBestEffort(
    913                 new String[] {option, value});
    914 
    915         assertTrue(object.mMyOption.isEmpty());
    916         assertEquals(2, leftovers.size());
    917         assertEquals(option, leftovers.get(0));
    918         assertEquals(value, leftovers.get(1));
    919     }
    920 
    921 
    922     // SECTION: help-related tests
    923     /**
    924      * Test that help text is displayed for all fields
    925      */
    926     public void testGetOptionHelp() {
    927         String help = ArgsOptionParser.getOptionHelp(false, new InheritedOptionSource());
    928         assertTrue(help.contains(InheritedOptionSource.OPTION_NAME));
    929         assertTrue(help.contains(InheritedOptionSource.OPTION_DESC));
    930         assertTrue(help.contains(OneOptionSource.OPTION_NAME));
    931         assertTrue(help.contains(OneOptionSource.OPTION_DESC));
    932         assertTrue(help.contains(OneOptionSource.DEFAULT_VALUE));
    933     }
    934 
    935     /**
    936      * Test displaying important only help text
    937      */
    938     public void testGetOptionHelp_important() {
    939         String help = ArgsOptionParser.getOptionHelp(true, new ImportantOptionSource());
    940         assertTrue(help.contains(ImportantOptionSource.IMPORTANT_OPTION_NAME));
    941         assertTrue(help.contains(ImportantOptionSource.IMPORTANT_UNSET_OPTION_NAME));
    942         assertFalse(help.contains(ImportantOptionSource.UNIMPORTANT_OPTION_NAME));
    943     }
    944 
    945     /**
    946      * Test that {@link Importance#IF_UNSET} {@link Option}s are hidden from help if set.
    947      */
    948     public void testGetOptionHelp_importantUnset() {
    949         String help = ArgsOptionParser.getOptionHelp(true, new ImportantOptionSource("foo"));
    950         assertTrue(help.contains(ImportantOptionSource.IMPORTANT_OPTION_NAME));
    951         assertFalse(help.contains(ImportantOptionSource.IMPORTANT_UNSET_OPTION_NAME));
    952         assertFalse(help.contains(ImportantOptionSource.UNIMPORTANT_OPTION_NAME));
    953     }
    954 
    955 
    956     // SECTION: mandatory option tests
    957     public void testMandatoryOption_noDefault() throws Exception {
    958         MandatoryOptionSourceNoDefault object = new MandatoryOptionSourceNoDefault();
    959         ArgsOptionParser parser = new ArgsOptionParser(object);
    960         // expect success
    961         parser.parse(new String[] {});
    962         try {
    963             parser.validateMandatoryOptions();
    964             fail("ConfigurationException not thrown");
    965         } catch (ConfigurationException e) {
    966             // expected
    967         }
    968     }
    969 
    970     public void testMandatoryOption_null() throws Exception {
    971         MandatoryOptionSourceNull object = new MandatoryOptionSourceNull();
    972         ArgsOptionParser parser = new ArgsOptionParser(object);
    973         parser.parse(new String[] {});
    974         try {
    975             parser.validateMandatoryOptions();
    976             fail("ConfigurationException not thrown");
    977         } catch (ConfigurationException e) {
    978             // expected
    979         }
    980     }
    981 
    982     public void testMandatoryOption_emptyCollection() throws Exception {
    983         MandatoryOptionSourceEmptyCollection object = new MandatoryOptionSourceEmptyCollection();
    984         ArgsOptionParser parser = new ArgsOptionParser(object);
    985         parser.parse(new String[] {});
    986         try {
    987             parser.validateMandatoryOptions();
    988             fail("ConfigurationException not thrown");
    989         } catch (ConfigurationException e) {
    990             // expected
    991         }
    992     }
    993 
    994     public void testMandatoryOption_emptyMap() throws Exception {
    995         MandatoryOptionSourceEmptyMap object = new MandatoryOptionSourceEmptyMap();
    996         ArgsOptionParser parser = new ArgsOptionParser(object);
    997         parser.parse(new String[] {});
    998         try {
    999             parser.validateMandatoryOptions();
   1000             fail("ConfigurationException not thrown");
   1001         } catch (ConfigurationException e) {
   1002             // expected
   1003         }
   1004     }
   1005 
   1006     // Key Store related
   1007     public void testKeyStore_string() throws Exception {
   1008         final String expectedValue = "set";
   1009         // Mock key store
   1010         IKeyStoreClient c = EasyMock.createNiceMock(IKeyStoreClient.class);
   1011         EasyMock.expect(c.isAvailable()).andReturn(true);
   1012         EasyMock.expect(c.containsKey("foo")).andStubReturn(true);
   1013         EasyMock.expect(c.fetchKey("foo")).andReturn(expectedValue);
   1014         EasyMock.replay(c);
   1015         OneOptionSource object = new OneOptionSource();
   1016         ArgsOptionParser parser = new ArgsOptionParser(object);
   1017         parser.setKeyStore(c);
   1018         parser.parse(new String[] {"--my_option", "USE_KEYSTORE@foo"});
   1019         // Key store value is set for the option as expected.
   1020         assertEquals(expectedValue, object.mMyOption);
   1021         EasyMock.verify(c);
   1022     }
   1023 
   1024     public void testKeyStore_stringWithNullKeyStore() throws Exception {
   1025         final String expectedValue = "set";
   1026         OneOptionSource object = new OneOptionSource();
   1027         ArgsOptionParser parser = new ArgsOptionParser(object);
   1028         parser.setKeyStore(null);
   1029         // An null key store should not affect normal operations.
   1030         parser.parse(new String[] {"--my_option", expectedValue});
   1031         assertEquals(expectedValue, object.mMyOption);
   1032     }
   1033 
   1034     public void testKeyStore_stringWithNullKeyStoreAndKey() throws Exception {
   1035         final String expectedValue = "";
   1036         OneOptionSource object = new OneOptionSource();
   1037         ArgsOptionParser parser = new ArgsOptionParser(object);
   1038         parser.setKeyStore(null);
   1039         // We try to fetch a key store value with null key store this should return an empty value.
   1040         try {
   1041             parser.parse(new String[] {"--my_option", "USE_KEYSTORE@foo"});
   1042         } catch (ConfigurationException e) {
   1043             //expected
   1044             return;
   1045         }
   1046         fail("ConfigurationException not thrown for attempted use of null keystore.");
   1047     }
   1048 
   1049     public void testKeyStore_stringWithUnavalableKeyStore() throws Exception {
   1050         final String expectedValue = "set";
   1051         // Mock key store
   1052         IKeyStoreClient c = EasyMock.createNiceMock(IKeyStoreClient.class);
   1053         EasyMock.expect(c.isAvailable()).andStubReturn(false);
   1054         EasyMock.replay(c);
   1055         OneOptionSource object = new OneOptionSource();
   1056         ArgsOptionParser parser = new ArgsOptionParser(object);
   1057         parser.setKeyStore(c);
   1058         // An unavailable key store should not affect normal operations.
   1059         parser.parse(new String[] {"--my_option", expectedValue});
   1060         assertEquals(expectedValue, object.mMyOption);
   1061         EasyMock.verify(c);
   1062     }
   1063 
   1064     public void testKeyStore_stringWithUnavalableKeyStoreWithKey() throws Exception {
   1065         final String expectedValue = "";
   1066         // Mock key store
   1067         IKeyStoreClient c = EasyMock.createNiceMock(IKeyStoreClient.class);
   1068         EasyMock.expect(c.isAvailable()).andReturn(false);
   1069         EasyMock.replay(c);
   1070         OneOptionSource object = new OneOptionSource();
   1071         ArgsOptionParser parser = new ArgsOptionParser(object);
   1072         parser.setKeyStore(c);
   1073         // We try to fetch a key store value with unavailable key store this should throw an
   1074         // exception
   1075         try {
   1076             parser.parse(new String[] {"--my_option", "USE_KEYSTORE@foo"});
   1077         } catch (ConfigurationException e) {
   1078             //expected
   1079             EasyMock.verify(c);
   1080             return;
   1081         }
   1082         fail("ConfiguationException not thrown for attempted use of unavailable keystore.");
   1083     }
   1084 
   1085     public void testKeyStore_stringWithUnavalableKey() throws Exception {
   1086         final String expectedValue = "";
   1087         // Mock key store
   1088         IKeyStoreClient c = EasyMock.createNiceMock(IKeyStoreClient.class);
   1089         EasyMock.expect(c.isAvailable()).andReturn(true);
   1090         EasyMock.expect(c.containsKey("foobar")).andStubReturn(true);
   1091         EasyMock.replay(c);
   1092         OneOptionSource object = new OneOptionSource();
   1093         ArgsOptionParser parser = new ArgsOptionParser(object);
   1094         parser.setKeyStore(c);
   1095         // We try to fetch a key store value with unavailable key this should throw an exception
   1096         try {
   1097             parser.parse(new String[] {"--my_option", "USE_KEYSTORE@foo"});
   1098         } catch (ConfigurationException e) {
   1099             //expected
   1100             EasyMock.verify(c);
   1101             return;
   1102         }
   1103         fail("ConfiguationException not thrown for attempted use of unavailable keystore.");
   1104     }
   1105 
   1106     public void testKeyStore_mapOptions() throws Exception {
   1107         final String option = "--my_option";
   1108         final String key = "hello";
   1109         final String value = "USE_KEYSTORE@foobar";
   1110         final String expKey = "hello";
   1111         final String expValue = "123";
   1112 
   1113         // Mock key store
   1114         IKeyStoreClient c = EasyMock.createNiceMock(IKeyStoreClient.class);
   1115         EasyMock.expect(c.isAvailable()).andReturn(true);
   1116         EasyMock.expect(c.containsKey("foobar")).andStubReturn(true);
   1117         EasyMock.expect(c.fetchKey("foobar")).andReturn(expValue);
   1118         EasyMock.replay(c);
   1119         MapStringOptionSource object = new MapStringOptionSource();
   1120         ArgsOptionParser parser = new ArgsOptionParser(object);
   1121         parser.setKeyStore(c);
   1122         // --option hello USE_KEYSTORE@foobar should give --option hello 123;
   1123         // where hello is set to 123
   1124         final List<String> leftovers = parser.parseBestEffort(
   1125                 new String[] {option, key, value});
   1126 
   1127         assertEquals(0, leftovers.size());
   1128         assertNotNull(object.mMyOption);
   1129         assertEquals(1, object.mMyOption.size());
   1130         assertTrue(object.mMyOption.containsKey(expKey));
   1131         assertEquals(expValue, object.mMyOption.get(expKey));
   1132         EasyMock.verify(c);
   1133     }
   1134 
   1135     public void testKeyStore_mapOptionsSingleValue() throws Exception {
   1136         final String option = "--my_option";
   1137         final String value = "hello=USE_KEYSTORE@foobar";
   1138         final String expKey = "hello";
   1139         final String expValue = "123";
   1140 
   1141         // Mock key store
   1142         IKeyStoreClient c = EasyMock.createNiceMock(IKeyStoreClient.class);
   1143         EasyMock.expect(c.isAvailable()).andReturn(true);
   1144         EasyMock.expect(c.containsKey("foobar")).andStubReturn(true);
   1145         EasyMock.expect(c.fetchKey("foobar")).andReturn(expValue);
   1146         EasyMock.replay(c);
   1147         MapStringOptionSource object = new MapStringOptionSource();
   1148         ArgsOptionParser parser = new ArgsOptionParser(object);
   1149         parser.setKeyStore(c);
   1150         // --option hello=USE_KEYSTORE@foobar should give --option hello=123
   1151         final List<String> leftovers = parser.parseBestEffort(
   1152                 new String[] {option, value});
   1153 
   1154         assertEquals(0, leftovers.size());
   1155         assertNotNull(object.mMyOption);
   1156         assertEquals(1, object.mMyOption.size());
   1157         assertTrue(object.mMyOption.containsKey(expKey));
   1158         assertEquals(expValue, object.mMyOption.get(expKey));
   1159         EasyMock.verify(c);
   1160 
   1161     }
   1162 
   1163     public void testKeyStore_mapOptionsMixedValue() throws Exception {
   1164         final String option = "--my_option";
   1165         final String value = "hello=123";
   1166         final String key2 = "byebye";
   1167         final String value2 = "USE_KEYSTORE@bar";
   1168         final String expKey = "hello";
   1169         final String expValue = "123";
   1170         final String expKey2 = "byebye";
   1171         final String expValue2 = "456";
   1172 
   1173         // Mock key store
   1174         IKeyStoreClient c = EasyMock.createNiceMock(IKeyStoreClient.class);
   1175         EasyMock.expect(c.isAvailable()).andReturn(true);
   1176         EasyMock.expect(c.containsKey("bar")).andStubReturn(true);
   1177         EasyMock.expect(c.fetchKey("bar")).andReturn(expValue2);
   1178         EasyMock.replay(c);
   1179         MapStringOptionSource object = new MapStringOptionSource();
   1180         ArgsOptionParser parser = new ArgsOptionParser(object);
   1181         parser.setKeyStore(c);
   1182 
   1183         final List<String> leftovers = parser.parseBestEffort(
   1184                 new String[] {option, key2, value2, option, value});
   1185 
   1186         assertEquals(0, leftovers.size());
   1187         assertNotNull(object.mMyOption);
   1188         assertEquals(2, object.mMyOption.size());
   1189 
   1190         assertTrue(object.mMyOption.containsKey(expKey2));
   1191         assertEquals(expValue2, object.mMyOption.get(expKey2));
   1192         assertTrue(object.mMyOption.containsKey(expKey));
   1193         assertEquals(expValue, object.mMyOption.get(expKey));
   1194         EasyMock.verify(c);
   1195     }
   1196 
   1197     public void testKeyStore_mapOptionsMixedValue_allKeys() throws Exception {
   1198         final String option = "--my_option";
   1199         final String value = "hello=USE_KEYSTORE@foobar";
   1200         final String key2 = "byebye";
   1201         final String value2 = "USE_KEYSTORE@bar";
   1202         final String expKey = "hello";
   1203         final String expValue = "123";
   1204         final String expKey2 = "byebye";
   1205         final String expValue2 = "456";
   1206 
   1207         // Mock key store
   1208         IKeyStoreClient c = EasyMock.createNiceMock(IKeyStoreClient.class);
   1209         EasyMock.expect(c.isAvailable()).andStubReturn(true);
   1210         EasyMock.expect(c.containsKey("foobar")).andStubReturn(true);
   1211         EasyMock.expect(c.fetchKey("foobar")).andReturn(expValue);
   1212         EasyMock.expect(c.containsKey("bar")).andStubReturn(true);
   1213         EasyMock.expect(c.fetchKey("bar")).andReturn(expValue2);
   1214         EasyMock.replay(c);
   1215         MapStringOptionSource object = new MapStringOptionSource();
   1216         ArgsOptionParser parser = new ArgsOptionParser(object);
   1217         parser.setKeyStore(c);
   1218 
   1219         final List<String> leftovers = parser.parseBestEffort(
   1220                 new String[] {option, key2, value2, option, value});
   1221 
   1222         assertEquals(0, leftovers.size());
   1223         assertNotNull(object.mMyOption);
   1224         assertEquals(2, object.mMyOption.size());
   1225 
   1226         assertTrue(object.mMyOption.containsKey(expKey2));
   1227         assertEquals(expValue2, object.mMyOption.get(expKey2));
   1228         assertTrue(object.mMyOption.containsKey(expKey));
   1229         assertEquals(expValue, object.mMyOption.get(expKey));
   1230         EasyMock.verify(c);
   1231     }
   1232 
   1233     /**
   1234      * Test that when the default {@link StubKeyStoreClient} is used and a keystore option is
   1235      * requested, we throw a configuration exception and no crash.
   1236      */
   1237     public void testKeyStore_StubKeystore_optionRequested() throws Exception {
   1238         final String expectedValue = "";
   1239         OneOptionSource object = new OneOptionSource();
   1240         ArgsOptionParser parser = new ArgsOptionParser(object);
   1241         parser.setKeyStore(new StubKeyStoreClient());
   1242         // We try to fetch a key store value with unavailable key this should throw an exception
   1243         try {
   1244             parser.parse(new String[] {"--my_option", "USE_KEYSTORE@foo"});
   1245         } catch (ConfigurationException e) {
   1246             //expected
   1247             return;
   1248         }
   1249         fail("ConfiguationException not thrown for attempted use of unavailable keystore.");
   1250     }
   1251 }
   1252