diff --git a/shell/src/main/java/org/apache/sqoop/shell/utils/ConfigFiller.java b/shell/src/main/java/org/apache/sqoop/shell/utils/ConfigFiller.java index 6a2a96d0..3a4a18d7 100644 --- a/shell/src/main/java/org/apache/sqoop/shell/utils/ConfigFiller.java +++ b/shell/src/main/java/org/apache/sqoop/shell/utils/ConfigFiller.java @@ -21,7 +21,6 @@ import org.apache.commons.cli.CommandLine; import org.apache.commons.lang.StringUtils; -import org.apache.sqoop.common.Direction; import org.apache.sqoop.model.InputEditable; import org.apache.sqoop.model.MBooleanInput; import org.apache.sqoop.model.MDateTimeInput; @@ -36,7 +35,6 @@ import org.apache.sqoop.model.MJob; import org.apache.sqoop.model.MNamedElement; import org.apache.sqoop.model.MStringInput; -import org.apache.sqoop.model.MValidatedElement; import org.apache.sqoop.validation.Message; import org.apache.sqoop.validation.Status; import org.joda.time.DateTime; @@ -229,7 +227,7 @@ public static boolean fillInput(String prefix, MInput input, CommandLine line) t * @return * @throws IOException */ - private static boolean fillInputDateTime(String prefix, + static boolean fillInputDateTime(String prefix, MDateTimeInput input, CommandLine line) throws IOException { @@ -250,14 +248,13 @@ private static boolean fillInputDateTime(String prefix, private static DateTime parseDateTime(String value) { DateTime dt = null; try { - dt = DateTime.parse(value); - } catch (IllegalArgumentException iae) { - // value is not valid ISO8601 format + dt = new DateTime(Long.parseLong(value)); + } catch (NumberFormatException nfe) { + // value is not numeric string try { - long a = Long.parseLong(value); - dt = new DateTime(a); - } catch (NumberFormatException nfe) { - // value is not numeric string + dt = DateTime.parse(value); + } catch (IllegalArgumentException iae) { + // value is not valid ISO8601 format } } return dt; @@ -274,7 +271,7 @@ private static DateTime parseDateTime(String value) { * @return * @throws IOException */ - private static boolean fillInputList(String prefix, + static boolean fillInputList(String prefix, MListInput input, CommandLine line) throws IOException { @@ -303,7 +300,7 @@ private static boolean fillInputList(String prefix, * @return * @throws IOException */ - private static boolean fillInputEnum(String prefix, + static boolean fillInputEnum(String prefix, MEnumInput input, CommandLine line) throws IOException { @@ -335,7 +332,7 @@ private static boolean fillInputEnum(String prefix, * @return * @throws IOException */ - private static boolean fillInputMap(String prefix, + static boolean fillInputMap(String prefix, MMapInput input, CommandLine line) throws IOException { @@ -343,9 +340,9 @@ private static boolean fillInputMap(String prefix, if (line.hasOption(opt)) { String value = line.getOptionValue(opt); Map values = new HashMap(); - String[] keyValue = null; String[] entries = value.split("&"); for (String entry : entries) { + String[] keyValue = null; if (entry.contains("=")) { keyValue = entry.split("=", 2); } @@ -372,7 +369,7 @@ private static boolean fillInputMap(String prefix, * @return * @throws IOException */ - private static boolean fillInputInteger(String prefix, + static boolean fillInputInteger(String prefix, MIntegerInput input, CommandLine line) throws IOException { @@ -402,7 +399,7 @@ private static boolean fillInputInteger(String prefix, * @return * @throws IOException */ - private static boolean fillInputLong(String prefix, MLongInput input, CommandLine line) throws IOException { + static boolean fillInputLong(String prefix, MLongInput input, CommandLine line) throws IOException { String opt = ConfigOptions.getOptionKey(prefix, input); if (line.hasOption(opt)) { try { @@ -426,7 +423,7 @@ private static boolean fillInputLong(String prefix, MLongInput input, CommandLin * @return * @throws IOException */ - public static boolean fillInputString(String prefix, + static boolean fillInputString(String prefix, MStringInput input, CommandLine line) throws IOException { @@ -436,6 +433,7 @@ public static boolean fillInputString(String prefix, if((input.getMaxLength() >= 0) && (value.length() > input.getMaxLength())) { errorMessage(input, "Size of input exceeds allowance for this input" + " field. Maximal allowed size is " + input.getMaxLength()); + return false; } input.setValue(value); } else { @@ -453,7 +451,7 @@ public static boolean fillInputString(String prefix, * @return * @throws IOException */ - public static boolean fillInputBoolean(String prefix, + static boolean fillInputBoolean(String prefix, MBooleanInput input, CommandLine line) throws IOException { @@ -586,9 +584,9 @@ static boolean fillInputWithBundle(MInput input, ConsoleReader reader, ResourceB case STRING: return fillInputStringWithBundle((MStringInput) input, reader, bundle); case INTEGER: - return fillInputInteger((MIntegerInput) input, reader, bundle); + return fillInputIntegerWithBundle((MIntegerInput) input, reader, bundle); case LONG: - return fillInputLong((MLongInput) input, reader, bundle); + return fillInputLongWithBundle((MLongInput) input, reader, bundle); case BOOLEAN: return fillInputBooleanWithBundle((MBooleanInput) input, reader, bundle); case MAP: @@ -622,7 +620,7 @@ static boolean fillInputWithBundle(MInput input, ConsoleReader reader, ResourceB * @return True if user wish to continue with loading additional inputs * @throws IOException */ - private static boolean fillInputDateTimeWithBundle(MDateTimeInput input, + static boolean fillInputDateTimeWithBundle(MDateTimeInput input, ConsoleReader reader, ResourceBundle bundle) throws IOException { @@ -669,7 +667,7 @@ private static boolean fillInputDateTimeWithBundle(MDateTimeInput input, * @return True if user wish to continue with loading additional inputs * @throws IOException */ - private static boolean fillInputListWithBundle(MListInput input, + static boolean fillInputListWithBundle(MListInput input, ConsoleReader reader, ResourceBundle bundle) throws IOException { @@ -735,7 +733,7 @@ private static boolean fillInputListWithBundle(MListInput input, * @return True if user with to continue with loading addtional inputs * @throws IOException */ - private static boolean fillInputEnumWithBundle(MEnumInput input, + static boolean fillInputEnumWithBundle(MEnumInput input, ConsoleReader reader, ResourceBundle bundle) throws IOException { @@ -767,6 +765,7 @@ private static boolean fillInputEnumWithBundle(MEnumInput input, } reader.flushConsole(); + String userTyped; if(input.isSensitive()) { userTyped = reader.readLine('*'); @@ -816,7 +815,7 @@ private static boolean fillInputEnumWithBundle(MEnumInput input, * @return True if user wish to continue with loading additional inputs * @throws IOException */ - private static boolean fillInputMapWithBundle(MMapInput input, + static boolean fillInputMapWithBundle(MMapInput input, ConsoleReader reader, ResourceBundle bundle) throws IOException { @@ -924,7 +923,7 @@ private static String handleUserInput(String input) { return input; } - private static boolean fillInputInteger(MIntegerInput input, + static boolean fillInputIntegerWithBundle(MIntegerInput input, ConsoleReader reader, ResourceBundle bundle) throws IOException { @@ -955,7 +954,7 @@ private static boolean fillInputInteger(MIntegerInput input, input.setValue(value); } catch (NumberFormatException ex) { errorMessage("Input is not valid integer number"); - return fillInputInteger(input, reader, bundle); + return fillInputIntegerWithBundle(input, reader, bundle); } input.setValue(Integer.valueOf(userTyped)); @@ -964,7 +963,7 @@ private static boolean fillInputInteger(MIntegerInput input, return true; } - private static boolean fillInputLong(MLongInput input, ConsoleReader reader, ResourceBundle bundle) throws IOException { + static boolean fillInputLongWithBundle(MLongInput input, ConsoleReader reader, ResourceBundle bundle) throws IOException { generatePrompt(reader, bundle, input); if (!input.isEmpty() && !input.isSensitive()) { @@ -990,7 +989,7 @@ private static boolean fillInputLong(MLongInput input, ConsoleReader reader, Res input.setValue(value); } catch (NumberFormatException ex) { errorMessage("Input is not a valid long"); - return fillInputLong(input, reader, bundle); + return fillInputLongWithBundle(input, reader, bundle); } input.setValue(Long.valueOf(userTyped)); @@ -1085,6 +1084,15 @@ static boolean fillInputBooleanWithBundle(MBooleanInput input, // Empty input in case that nothing was given input.setEmpty(); } else { + Boolean value; + try { + value = Boolean.valueOf(userTyped); + input.setValue(value); + } catch (NumberFormatException ex) { + errorMessage("Input is not a valid boolean"); + return fillInputBooleanWithBundle(input, reader, bundle); + } + // Set value that user has entered input.setValue(Boolean.valueOf(userTyped)); } diff --git a/shell/src/test/java/org/apache/sqoop/shell/utils/TestConfigFiller.java b/shell/src/test/java/org/apache/sqoop/shell/utils/TestConfigFiller.java new file mode 100644 index 00000000..1917a1d0 --- /dev/null +++ b/shell/src/test/java/org/apache/sqoop/shell/utils/TestConfigFiller.java @@ -0,0 +1,479 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.sqoop.shell.utils; + +import static org.apache.sqoop.shell.utils.ConfigFiller.*; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNull; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.ResourceBundle; + +import jline.ConsoleReader; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.lang.StringUtils; +import org.apache.sqoop.model.InputEditable; +import org.apache.sqoop.model.MBooleanInput; +import org.apache.sqoop.model.MDateTimeInput; +import org.apache.sqoop.model.MEnumInput; +import org.apache.sqoop.model.MIntegerInput; +import org.apache.sqoop.model.MListInput; +import org.apache.sqoop.model.MLongInput; +import org.apache.sqoop.model.MMapInput; +import org.apache.sqoop.model.MStringInput; +import org.apache.sqoop.shell.ShellEnvironment; +import org.codehaus.groovy.tools.shell.Groovysh; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +public class TestConfigFiller { + CommandLine line; + ConsoleReader reader; + ResourceBundle resourceBundle; + ByteArrayInputStream in; + byte[] data; + + @BeforeTest(alwaysRun = true) + public void setup() throws IOException { + Groovysh shell = new Groovysh(); + ShellEnvironment.setIo(shell.getIo()); + line = mock(CommandLine.class); + data = new byte[1000]; + in = new ByteArrayInputStream(data); + reader = new ConsoleReader(in, new OutputStreamWriter(System.out)); + resourceBundle = new ResourceBundle() { + @Override + protected Object handleGetObject(String key) { + return "fake_translated_value"; + } + + @Override + public Enumeration getKeys() { + return Collections.emptyEnumeration(); + } + }; + } + + @SuppressWarnings("unchecked") + @Test + public void testFillInputString() throws IOException { + MStringInput input = new MStringInput("String", false, InputEditable.ANY, StringUtils.EMPTY, (short)30, Collections.EMPTY_LIST); + when(line.hasOption("prefix-String")).thenReturn(false); + assertTrue(fillInputString("prefix", input, line)); + assertNull(input.getValue()); + + input.setEmpty(); + when(line.hasOption("prefix-String")).thenReturn(true); + when(line.getOptionValue("prefix-String")).thenReturn("abc"); + assertTrue(fillInputString("prefix", input, line)); + assertEquals(input.getValue(), "abc"); + + input.setEmpty(); + String lengthExceeds30 = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"; + when(line.getOptionValue("prefix-String")).thenReturn(lengthExceeds30); + assertFalse(fillInputString("prefix", input, line)); + } + + @SuppressWarnings("unchecked") + @Test + public void testFillInputStringWithBundle() throws IOException { + initEnv(); + // End of the process + MStringInput input = new MStringInput("String", false, InputEditable.ANY, StringUtils.EMPTY, (short)30, Collections.EMPTY_LIST); + assertFalse(fillInputStringWithBundle(input, reader, resourceBundle)); + + // Empty input + initData("\r"); + input.setEmpty(); + assertTrue(fillInputStringWithBundle(input, reader, resourceBundle)); + assertNull(input.getValue()); + + // Normal input + initData("abc\r"); + input.setEmpty(); + assertTrue(fillInputStringWithBundle(input, reader, resourceBundle)); + assertEquals(input.getValue(), "abc"); + + // Retry when the given input exceeds maximal allowance + String lengthExceeds30 = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"; + String remove30characters = "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"; + String lengthBelowLimit = "abcdefg"; + initData(lengthExceeds30 + "\r" + remove30characters + lengthBelowLimit + "\r"); + input.setEmpty(); + assertTrue(fillInputStringWithBundle(input, reader, resourceBundle)); + assertEquals(input.getValue(), lengthBelowLimit); + } + + @SuppressWarnings("unchecked") + @Test + public void testFillInputInteger() throws IOException { + MIntegerInput input = new MIntegerInput("Integer", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST); + when(line.hasOption("prefix-Integer")).thenReturn(false); + assertTrue(fillInputInteger("prefix", input, line)); + assertNull(input.getValue()); + + // Valid integer number + input.setEmpty(); + when(line.hasOption("prefix-Integer")).thenReturn(true); + when(line.getOptionValue("prefix-Integer")).thenReturn("12345"); + assertTrue(fillInputInteger("prefix", input, line)); + assertEquals(input.getValue().intValue(), 12345); + + // Invalid integer number + input.setEmpty(); + when(line.hasOption("prefix-Integer")).thenReturn(true); + when(line.getOptionValue("prefix-Integer")).thenReturn("abc"); + assertFalse(fillInputInteger("prefix", input, line)); + } + + @SuppressWarnings("unchecked") + @Test + public void testFillInputIntegerWithBundle() throws IOException { + initEnv(); + // End of the process + MIntegerInput input = new MIntegerInput("Integer", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST); + assertFalse(fillInputIntegerWithBundle(input, reader, resourceBundle)); + + // Empty input + initData("\r"); + input.setEmpty(); + assertTrue(fillInputIntegerWithBundle(input, reader, resourceBundle)); + assertNull(input.getValue()); + + // Normal input + initData("12345\r"); + input.setEmpty(); + assertTrue(fillInputIntegerWithBundle(input, reader, resourceBundle)); + assertEquals(input.getValue().intValue(), 12345); + + // Retry when the given input is not a valid integer number + initData("abc\r12345\r"); + input.setEmpty(); + assertTrue(fillInputIntegerWithBundle(input, reader, resourceBundle)); + assertEquals(input.getValue().intValue(), 12345); + } + + @SuppressWarnings("unchecked") + @Test + public void testFillInputLong() throws IOException { + MLongInput input = new MLongInput("Long", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST); + when(line.hasOption("prefix-Long")).thenReturn(false); + assertTrue(fillInputLong("prefix", input, line)); + assertNull(input.getValue()); + + // Valid long number + input.setEmpty(); + when(line.hasOption("prefix-Long")).thenReturn(true); + when(line.getOptionValue("prefix-Long")).thenReturn("12345"); + assertTrue(fillInputLong("prefix", input, line)); + assertEquals(input.getValue().longValue(), 12345); + + // Invalid long number + input.setEmpty(); + when(line.hasOption("prefix-Long")).thenReturn(true); + when(line.getOptionValue("prefix-Long")).thenReturn("abc"); + assertFalse(fillInputLong("prefix", input, line)); + } + + @SuppressWarnings("unchecked") + @Test + public void testFillInputLongWithBundle() throws IOException { + initEnv(); + // End of the process + MLongInput input = new MLongInput("Long", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST); + assertFalse(fillInputLongWithBundle(input, reader, resourceBundle)); + + // Empty input + initData("\r"); + input.setEmpty(); + assertTrue(fillInputLongWithBundle(input, reader, resourceBundle)); + assertNull(input.getValue()); + + // Normal input + initData("12345\r"); + input.setEmpty(); + assertTrue(fillInputLongWithBundle(input, reader, resourceBundle)); + assertEquals(input.getValue().intValue(), 12345); + + // Retry when the given input is not a valid long number + initData("abc\r12345\r"); + input.setEmpty(); + assertTrue(fillInputLongWithBundle(input, reader, resourceBundle)); + assertEquals(input.getValue().intValue(), 12345); + } + + @SuppressWarnings("unchecked") + @Test + public void testFillInputBoolean() throws IOException { + MBooleanInput input = new MBooleanInput("Boolean", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST); + when(line.hasOption("prefix-Boolean")).thenReturn(false); + assertTrue(fillInputBoolean("prefix", input, line)); + assertNull(input.getValue()); + + // true + input.setEmpty(); + when(line.hasOption("prefix-Boolean")).thenReturn(true); + when(line.getOptionValue("prefix-Boolean")).thenReturn("true"); + assertTrue(fillInputBoolean("prefix", input, line)); + assertTrue(input.getValue()); + + // false + input.setEmpty(); + when(line.hasOption("prefix-Boolean")).thenReturn(true); + when(line.getOptionValue("prefix-Boolean")).thenReturn("false"); + assertTrue(fillInputBoolean("prefix", input, line)); + assertFalse(input.getValue()); + } + + @SuppressWarnings("unchecked") + @Test + public void testFillInputBooleanWithBundle() throws IOException { + initEnv(); + // End of the process + MBooleanInput input = new MBooleanInput("Boolean", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST); + assertFalse(fillInputBooleanWithBundle(input, reader, resourceBundle)); + + // true + initData("true\r"); + input.setEmpty(); + assertTrue(fillInputBooleanWithBundle(input, reader, resourceBundle)); + assertTrue(input.getValue()); + + // false + initData("false\r"); + input.setEmpty(); + assertTrue(fillInputBooleanWithBundle(input, reader, resourceBundle)); + assertFalse(input.getValue()); + + // Retry when the given input is not a valid boolean number + initData("abc\rfalse\r"); + input.setEmpty(); + assertTrue(fillInputBooleanWithBundle(input, reader, resourceBundle)); + assertFalse(input.getValue()); + } + + @SuppressWarnings("unchecked") + @Test + public void testFillInputMap() throws IOException { + MMapInput input = new MMapInput("Map", false, InputEditable.ANY, StringUtils.EMPTY, StringUtils.EMPTY, Collections.EMPTY_LIST); + when(line.hasOption("prefix-Map")).thenReturn(false); + assertTrue(fillInputMap("prefix", input, line)); + + // Normal input + input.setEmpty(); + when(line.hasOption("prefix-Map")).thenReturn(true); + when(line.getOptionValue("prefix-Map")).thenReturn("k1=v1&k2=v2"); + assertTrue(fillInputMap("prefix", input, line)); + HashMap map = new HashMap(); + map.put("k1", "v1"); + map.put("k2", "v2"); + assertEquals(input.getValue(), map); + + // Invalid input + input.setEmpty(); + when(line.hasOption("prefix-Map")).thenReturn(true); + when(line.getOptionValue("prefix-Map")).thenReturn("k1=v1&k2"); + assertFalse(fillInputMap("prefix", input, line)); + } + + @SuppressWarnings("unchecked") + @Test + public void testFillInputMapWithBundle() throws IOException { + initEnv(); + // End of the process + MMapInput input = new MMapInput("Map", false, InputEditable.ANY, StringUtils.EMPTY, StringUtils.EMPTY, Collections.EMPTY_LIST); + assertFalse(fillInputMapWithBundle(input, reader, resourceBundle)); + + // empty + initData("\r"); + input.setEmpty(); + assertTrue(fillInputMapWithBundle(input, reader, resourceBundle)); + + // Add k1=v1 and k2=v2 + initData("k1=v1\rk2=v2\r\r"); + input.setEmpty(); + assertTrue(fillInputMapWithBundle(input, reader, resourceBundle)); + HashMap map = new HashMap(); + map.put("k1", "v1"); + map.put("k2", "v2"); + assertEquals(input.getValue(), map); + + // Remove k2 + initData("k2\r\r"); + assertTrue(fillInputMapWithBundle(input, reader, resourceBundle)); + map.remove("k2"); + assertEquals(input.getValue(), map); + } + + @SuppressWarnings("unchecked") + @Test + public void testFillInputEnum() throws IOException { + MEnumInput input = new MEnumInput("Enum", false, InputEditable.ANY, StringUtils.EMPTY, new String[] {"YES", "NO"}, Collections.EMPTY_LIST); + when(line.hasOption("prefix-Enum")).thenReturn(false); + assertTrue(fillInputEnum("prefix", input, line)); + assertNull(input.getValue()); + + // Normal input + input.setEmpty(); + when(line.hasOption("prefix-Enum")).thenReturn(true); + when(line.getOptionValue("prefix-Enum")).thenReturn("YES"); + assertTrue(fillInputEnum("prefix", input, line)); + assertEquals(input.getValue(), "YES"); + + // Invalid input + input.setEmpty(); + when(line.hasOption("prefix-Enum")).thenReturn(true); + when(line.getOptionValue("prefix-Enum")).thenReturn("NONEXISTVALUE"); + assertFalse(fillInputEnum("prefix", input, line)); + } + + @SuppressWarnings("unchecked") + @Test + public void testFillInputEnumWithBundle() throws IOException { + initEnv(); + // End of the process + MEnumInput input = new MEnumInput("Enum", false, InputEditable.ANY, StringUtils.EMPTY, new String[] {"YES", "NO"}, Collections.EMPTY_LIST); + assertFalse(fillInputEnumWithBundle(input, reader, resourceBundle)); + + // empty + initData("\r"); + input.setEmpty(); + assertTrue(fillInputEnumWithBundle(input, reader, resourceBundle)); + + // YES + initData("0\r"); + input.setEmpty(); + assertTrue(fillInputEnumWithBundle(input, reader, resourceBundle)); + assertEquals(input.getValue(), "YES"); + + // Retry when the given input is not a valid boolean number + initData("a\r1\r"); + input.setEmpty(); + assertTrue(fillInputEnumWithBundle(input, reader, resourceBundle)); + assertEquals(input.getValue(), "NO"); + } + + @SuppressWarnings("unchecked") + @Test + public void testFillInputList() throws IOException { + MListInput input = new MListInput("List", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST); + when(line.hasOption("prefix-List")).thenReturn(false); + assertTrue(fillInputList("prefix", input, line)); + assertNull(input.getValue()); + + // Normal input + input.setEmpty(); + when(line.hasOption("prefix-List")).thenReturn(true); + when(line.getOptionValue("prefix-List")).thenReturn("l1&l2&l3"); + assertTrue(fillInputList("prefix", input, line)); + assertEquals(StringUtils.join(input.getValue(), "&"), "l1&l2&l3"); + } + + @SuppressWarnings("unchecked") + @Test + public void testFillInputListWithBundle() throws IOException { + initEnv(); + // End of the process + MListInput input = new MListInput("List", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST); + assertFalse(fillInputListWithBundle(input, reader, resourceBundle)); + + // empty + initData("\r"); + input.setEmpty(); + assertTrue(fillInputListWithBundle(input, reader, resourceBundle)); + + // Normal input + initData("l1\rl2\rl3\r\r"); + input.setEmpty(); + assertTrue(fillInputListWithBundle(input, reader, resourceBundle)); + assertEquals(StringUtils.join(input.getValue(), "&"), "l1&l2&l3"); + } + + @SuppressWarnings("unchecked") + @Test + public void testFillInputDateTime() throws IOException { + MDateTimeInput input = new MDateTimeInput("DateTime", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST); + when(line.hasOption("prefix-DateTime")).thenReturn(false); + assertTrue(fillInputDateTime("prefix", input, line)); + assertNull(input.getValue()); + + // Normal input + input.setEmpty(); + when(line.hasOption("prefix-DateTime")).thenReturn(true); + when(line.getOptionValue("prefix-DateTime")).thenReturn("123456789"); + assertTrue(fillInputDateTime("prefix", input, line)); + assertEquals(input.getValue().getMillis(), 123456789); + + // Invalid input + input.setEmpty(); + when(line.hasOption("prefix-DateTime")).thenReturn(true); + when(line.getOptionValue("prefix-DateTime")).thenReturn("abcd"); + assertFalse(fillInputDateTime("prefix", input, line)); + } + + @SuppressWarnings("unchecked") + @Test + public void testFillInputDateTimeWithBundle() throws IOException { + initEnv(); + // End of the process + MDateTimeInput input = new MDateTimeInput("DateTime", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST); + assertFalse(fillInputDateTimeWithBundle(input, reader, resourceBundle)); + + // empty + initData("\r"); + input.setEmpty(); + assertTrue(fillInputDateTimeWithBundle(input, reader, resourceBundle)); + + // Normal input + initData("123456789\r"); + input.setEmpty(); + assertTrue(fillInputDateTimeWithBundle(input, reader, resourceBundle)); + assertEquals(input.getValue().getMillis(), 123456789); + + // Retry when the given input is not valid datetime + initData("abc\r123456789\r"); + input.setEmpty(); + assertTrue(fillInputDateTimeWithBundle(input, reader, resourceBundle)); + assertEquals(input.getValue().getMillis(), 123456789); + } + + private void initData(String destData) { + byte[] destDataBytes = destData.getBytes(); + System.arraycopy(destDataBytes, 0, data, 0, destDataBytes.length); + in.reset(); + } + + private void initEnv() { + in.reset(); + for (int i = 0; i < data.length; i++) { + data[i] = '\0'; + } + } +}