Bug 574779: [ToolService] Fix BasicToolCommandHandler

Follow-up-to: 08f43ec00d4cd05cbe6e4cecd26b0e824a742cd3
Change-Id: Ia3c3d657c9b15579d949dab502fc6a1130fada50
diff --git a/jcommons/org.eclipse.statet.jcommons.util-tests/src/org/eclipse/statet/jcommons/ts/core/BasicToolCommandDataTest.java b/jcommons/org.eclipse.statet.jcommons.util-tests/src/org/eclipse/statet/jcommons/ts/core/BasicToolCommandDataTest.java
new file mode 100644
index 0000000..2233b2a
--- /dev/null
+++ b/jcommons/org.eclipse.statet.jcommons.util-tests/src/org/eclipse/statet/jcommons/ts/core/BasicToolCommandDataTest.java
@@ -0,0 +1,317 @@
+/*=============================================================================#
+ # Copyright (c) 2021 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.jcommons.ts.core;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Map;
+
+import org.junit.jupiter.api.Test;
+
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+
+
+@NonNullByDefault
+public class BasicToolCommandDataTest {
+	
+	
+	private final String[] value1= new String[] { "foo" };
+	private final Object value2= new java.util.Random();
+	private final String valueString= "foobar";
+	private final String[] valueStringArray= new String[] { "foobar", "second" };
+	private final Object[] valueStringArrayNull= new Object[] { null };
+	private final Boolean valueBoolean= Boolean.TRUE;
+	private final Integer valueInt= Integer.valueOf(1234);
+	private final Double valueDouble= Double.valueOf(1234);
+	private final Object[] valueObjectArrayString= new Object[] { "abc" };
+	
+	
+	public BasicToolCommandDataTest() {
+	}
+	
+	
+	private BasicToolCommandData createData() {
+		return new BasicToolCommandData(Map.of(
+				"key1", this.value1,
+				"key2", this.value2,
+				"keyString", this.valueString,
+				"keyStringArray", this.valueStringArray,
+				"keyStringArrayNull", this.valueStringArrayNull,
+				"keyBoolean", this.valueBoolean,
+				"keyInt", this.valueInt,
+				"keyDouble", this.valueDouble,
+				"keyObjectArrayString", this.valueObjectArrayString
+				));
+	}
+	
+	@Test
+	public void getRawData() {
+		final ToolCommandData data= createData();
+		
+		assertIdentical(this.value1, data.getRawData("key1"));
+		assertIdentical(this.value2, data.getRawData("key2"));
+	}
+	
+	@Test
+	public void getRawData_missing() {
+		final ToolCommandData data= createData();
+		
+		assertNull(data.getRawData("keyMissing"));
+	}
+	
+	@Test
+	@SuppressWarnings("null")
+	public void getRawData_argCheck() {
+		final ToolCommandData data= createData();
+		
+		assertThrows(NullPointerException.class, () -> {
+			data.getRawData(null);
+		});
+	}
+	
+	
+	@Test
+	public void get() {
+		final ToolCommandData data= createData();
+		
+		assertIdentical(this.value1, data.get("key1", String[].class));
+		assertIdentical(this.value2, data.get("key2", Object.class));
+	}
+	
+	@Test
+	public void get_missing() {
+		final ToolCommandData data= createData();
+		
+		assertNull(data.get("keyMissing", String[].class));
+	}
+	
+	@Test
+	public void get_convert() {
+		final ToolCommandData data= createData();
+		
+		assertEquals("foo", data.get("key1", String.class));
+		
+		assertThrows(ToolCommandData.IllegalDataException.class, () -> {
+			data.get("key1", Map.class);
+		});
+	}
+	
+	@Test
+	@SuppressWarnings("null")
+	public void get_argCheck() {
+		final ToolCommandData data= createData();
+		
+		assertThrows(NullPointerException.class, () -> {
+			data.get(null, String[].class);
+		});
+		assertThrows(NullPointerException.class, () -> {
+			data.get("key1", null);
+		});
+	}
+	
+	
+	@Test
+	public void getDefault() {
+		final ToolCommandData data= createData();
+		
+		assertIdentical(this.value1, data.get("key1", String[].class, new String[] {}));
+		assertIdentical(this.value2, data.get("key2", Object.class, new Object()));
+	}
+	
+	@Test
+	public void getDefault_missing() {
+		final ToolCommandData data= createData();
+		final String[] defaultValue= new String[0];
+		
+		assertIdentical(defaultValue, data.get("keyMissing", String[].class, defaultValue));
+	}
+	
+	@Test
+	public void getDefault_convert() {
+		final ToolCommandData data= createData();
+		
+		assertEquals("foo", data.get("key1", String.class, "bar"));
+		
+		assertThrows(ToolCommandData.IllegalDataException.class, () -> {
+			data.get("key1", Map.class, Map.of());
+		});
+	}
+	
+	@Test
+	@SuppressWarnings("null")
+	public void getDefault_argCheck() {
+		final ToolCommandData data= createData();
+		
+		assertThrows(NullPointerException.class, () -> {
+			data.get(null, String[].class, new String[0]);
+		});
+		assertThrows(NullPointerException.class, () -> {
+			data.get("key1", null, new String[0]);
+		});
+	}
+	
+	
+	@Test
+	public void getRequired() {
+		final ToolCommandData data= createData();
+		
+		assertIdentical(this.value1, data.getRequired("key1", String[].class));
+		assertIdentical(this.value2, data.getRequired("key2", Object.class));
+	}
+	
+	@Test
+	public void getRequired_missing() {
+		final ToolCommandData data= createData();
+		
+		assertThrows(ToolCommandData.IllegalDataException.class, () -> {
+			data.getRequired("key1", Map.class);
+		});
+	}
+	
+	@Test
+	public void getRequired_convert() {
+		final ToolCommandData data= createData();
+		
+		assertEquals("foo", data.getRequired("key1", String.class));
+		
+		assertThrows(ToolCommandData.IllegalDataException.class, () -> {
+			data.getRequired("key1", Map.class);
+		});
+	}
+	
+	@Test
+	@SuppressWarnings("null")
+	public void getRequired_argCheck() {
+		final ToolCommandData data= createData();
+		
+		assertThrows(NullPointerException.class, () -> {
+			data.getRequired(null, String[].class);
+		});
+		assertThrows(NullPointerException.class, () -> {
+			data.getRequired("key1", null);
+		});
+	}
+	
+	
+	@Test
+	public void convertSingleValue() {
+		final ToolCommandData data= createData();
+		
+		assertEquals(this.value1[0], data.get("key1", String.class));
+		assertEquals("abc", data.get("keyObjectArrayString", String.class));
+		assertThrows(ToolCommandData.IllegalDataException.class, () -> {
+			data.getRequired("keyStringArray", String.class);
+		});
+		assertThrows(ToolCommandData.IllegalDataException.class, () -> {
+			data.getRequired("keyStringArrayNull", String.class);
+		});
+	}
+	
+	@Test
+	public void convertInt() {
+		final ToolCommandData data= createData();
+		
+		assertEquals(this.valueDouble.intValue(), data.get("keyDouble", Integer.class));
+		assertThrows(ToolCommandData.IllegalDataException.class, () -> {
+			data.getRequired("key2", Integer.class);
+		});
+	}
+	
+	@Test
+	public void convertDouble() {
+		final ToolCommandData data= createData();
+		
+		assertEquals(this.valueInt.intValue(), data.get("keyInt", Double.class));
+		assertThrows(ToolCommandData.IllegalDataException.class, () -> {
+			data.getRequired("key2", Double.class);
+		});
+	}
+	
+	
+	@Test
+	public void getString() {
+		final ToolCommandData data= createData();
+		
+		assertEquals(this.valueString, data.getString("keyString"));
+		assertNull(data.getString("keyMissing"));
+		
+		assertEquals(this.valueString, data.getString("keyString", "xxx"));
+		assertEquals("xxx", data.getString("keyMissing", "xxx"));
+		
+		assertEquals(this.valueString, data.getStringRequired("keyString"));
+		assertThrows(ToolCommandData.IllegalDataException.class, () -> {
+			data.getStringRequired("keyMissing");
+		});
+	}
+	
+	@Test
+	public void getBoolean() {
+		final ToolCommandData data= createData();
+		
+		assertEquals(this.valueBoolean, data.getBoolean("keyBoolean", false));
+		assertEquals(false, data.getBoolean("keyMissing", false));
+		
+		assertEquals(this.valueBoolean, data.getBooleanRequired("keyBoolean"));
+		assertThrows(ToolCommandData.IllegalDataException.class, () -> {
+			data.getBooleanRequired("keyMissing");
+		});
+	}
+	
+	@Test
+	public void getInt() {
+		final ToolCommandData data= createData();
+		
+		assertEquals(this.valueInt, data.getInt("keyInt", -1));
+		assertEquals(-1, data.getInt("keyMissing", -1));
+		
+		assertEquals(this.valueInt, data.getIntRequired("keyInt"));
+		assertThrows(ToolCommandData.IllegalDataException.class, () -> {
+			data.getIntRequired("keyMissing");
+		});
+	}
+	
+	
+	@Test
+	public void ReturnData() {
+		final BasicToolCommandData data= createData();
+		
+		assertFalse(data.hasReturnData());
+		
+		data.setReturnData("keyReturn1", "returnValue");
+		data.setReturnData("keyReturn2", 123);
+		data.setReturnData("key1", "overwritten");
+		
+		assertTrue(data.hasReturnData());
+		assertEquals(3, data.getReturnData().size());
+		assertEquals("returnValue", data.getReturnData().get("keyReturn1"));
+		
+		data.removeReturnData("keyReturn2");
+		assertTrue(data.hasReturnData());
+		assertEquals(2, data.getReturnData().size());
+		assertEquals("returnValue", data.getReturnData().get("keyReturn1"));
+		
+		assertEquals("overwritten", data.get("key1", String.class));
+	}
+	
+	
+	private static void assertIdentical(final Object expected, final Object actual) {
+		assertTrue(expected == actual);
+	}
+	
+}
diff --git a/jcommons/org.eclipse.statet.jcommons.util/src/org/eclipse/statet/jcommons/ts/core/BasicToolCommandData.java b/jcommons/org.eclipse.statet.jcommons.util/src/org/eclipse/statet/jcommons/ts/core/BasicToolCommandData.java
index cda6e8c..280b37e 100644
--- a/jcommons/org.eclipse.statet.jcommons.util/src/org/eclipse/statet/jcommons/ts/core/BasicToolCommandData.java
+++ b/jcommons/org.eclipse.statet.jcommons.util/src/org/eclipse/statet/jcommons/ts/core/BasicToolCommandData.java
@@ -41,7 +41,7 @@
 	
 	@Override
 	public @Nullable Object getRawData(final String key) {
-		return this.data;
+		return this.data.get(key);
 	}
 	
 	protected @Nullable Object getData(final String key) {
@@ -61,9 +61,9 @@
 				return (TData)rawData;
 			}
 			else {
-				final TData typedData= convert(rawData, type);
+				final var typedData= convert(rawData, type);
 				if (typedData == null) {
-					throw new IllegalArgumentException(String.format("Data entry '%1$s' is incompatible (%2$s).",
+					throw new IllegalDataException(String.format("Data entry '%1$s' is incompatible (%2$s).",
 							key, rawData.getClass().getName() ));
 				}
 				return typedData;