PROTON-2569 Fixes and some tests for client options clone API
diff --git a/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/ClientOptions.java b/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/ClientOptions.java
index 6c612c2..4d475ce 100644
--- a/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/ClientOptions.java
+++ b/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/ClientOptions.java
@@ -19,7 +19,7 @@
 /**
  * Container Options for customizing the behavior of the Container
  */
-public class ClientOptions {
+public class ClientOptions implements Cloneable {
 
     private String id;
     private String futureType;
@@ -95,12 +95,12 @@
      * @param other
      *      the target of this copy operation.
      *
-     * @return this options class for chaining.
+     * @return the {@link ClientOptions} instance that was given.
      */
-    public ClientOptions copyInto(ClientOptions other) {
+    protected ClientOptions copyInto(ClientOptions other) {
         other.id(id);
         other.futureType(futureType);
 
-        return this;
+        return other;
     }
 }
diff --git a/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/ConnectionOptions.java b/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/ConnectionOptions.java
index da4bf22..f369cb5 100644
--- a/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/ConnectionOptions.java
+++ b/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/ConnectionOptions.java
@@ -29,9 +29,9 @@
 import org.apache.qpid.protonj2.types.transport.Open;
 
 /**
- * Options that control the behaviour of the {@link Connection} created from them.
+ * Options that control the behavior of the {@link Connection} created from them.
  */
-public class ConnectionOptions {
+public class ConnectionOptions implements Cloneable {
 
     /**
      * Default value for the AMQP desired capabilities set in the Open frame.
@@ -111,7 +111,7 @@
      * @param other
      *      the target of this copy operation.
      *
-     * @return this {@link ConnectionOptions} instance.
+     * @return the {@link ConnectionOptions} instance that was given.
      */
     protected ConnectionOptions copyInto(ConnectionOptions other) {
         other.closeTimeout(closeTimeout);
@@ -146,7 +146,7 @@
         sasl.copyInto(other.saslOptions());
         reconnect.copyInto(other.reconnectOptions());
 
-        return this;
+        return other;
     }
 
     /**
diff --git a/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/OutputStreamOptions.java b/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/OutputStreamOptions.java
index 5dc2da1..6900b0d 100644
--- a/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/OutputStreamOptions.java
+++ b/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/OutputStreamOptions.java
@@ -24,7 +24,7 @@
  * Options class that controls various aspects of a {@link OutputStream} instance created to write
  * the contents of a section of a {@link StreamSenderMessage}.
  */
-public class OutputStreamOptions {
+public class OutputStreamOptions implements Cloneable {
 
     /**
      * Defines the default value for the complete parent {@link StreamSenderMessage} on close option
@@ -65,13 +65,13 @@
      * @param other
      *      the target of this copy operation.
      *
-     * @return this {@link OutputStreamOptions} class for chaining.
+     * @return the {@link OutputStreamOptions} that was given.
      */
     protected OutputStreamOptions copyInto(OutputStreamOptions other) {
         other.bodyLength(streamSize);
         other.completeSendOnClose(completeSendOnClose);
 
-        return this;
+        return other;
     }
 
     /**
diff --git a/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/ReceiverOptions.java b/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/ReceiverOptions.java
index fa7f387..78f58e0 100644
--- a/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/ReceiverOptions.java
+++ b/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/ReceiverOptions.java
@@ -21,7 +21,7 @@
 /**
  * Options that control the behavior of the {@link Receiver} created from them.
  */
-public class ReceiverOptions extends LinkOptions<ReceiverOptions> {
+public class ReceiverOptions extends LinkOptions<ReceiverOptions> implements Cloneable {
 
     private long drainTimeout = ConnectionOptions.DEFAULT_DRAIN_TIMEOUT;
     private boolean autoAccept = true;
@@ -140,7 +140,7 @@
      * @param other
      *      the target of this copy operation.
      *
-     * @return this options class for chaining.
+     * @return the {@link ReceiverOptions} instance that was given.
      */
     protected ReceiverOptions copyInto(ReceiverOptions other) {
         super.copyInto(other);
@@ -149,7 +149,7 @@
         other.creditWindow(creditWindow);
         other.drainTimeout(drainTimeout);
 
-        return this;
+        return other;
     }
 
     @Override
diff --git a/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/ReconnectOptions.java b/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/ReconnectOptions.java
index b21edf4..4c0fe40 100644
--- a/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/ReconnectOptions.java
+++ b/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/ReconnectOptions.java
@@ -23,7 +23,7 @@
 /**
  * Options that control the reconnection behavior of a client {@link Connection}.
  */
-public class ReconnectOptions {
+public class ReconnectOptions implements Cloneable {
 
     public static final boolean DEFAULT_RECONNECT_ENABLED = false;
     public static final int INFINITE = -1;
@@ -62,6 +62,11 @@
         }
     }
 
+    @Override
+    public ReconnectOptions clone() {
+        return copyInto(new ReconnectOptions());
+    }
+
     /**
      * Copy all options from this {@link ReconnectOptions} instance into the instance
      * provided.
@@ -69,7 +74,7 @@
      * @param other
      *      the target of this copy operation.
      *
-     * @return this {@link ReconnectOptions} instance.
+     * @return the {@link ReconnectOptions} instance that was given.
      */
     protected ReconnectOptions copyInto(ReconnectOptions other) {
         other.reconnectEnabled(reconnectEnabled());
@@ -82,7 +87,7 @@
         other.reconnectBackOffMultiplier(reconnectBackOffMultiplier);
         other.reconnectHosts.addAll(reconnectHosts);
 
-        return this;
+        return other;
     }
 
     /**
diff --git a/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/SenderOptions.java b/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/SenderOptions.java
index 8e3cba2..77c4990 100644
--- a/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/SenderOptions.java
+++ b/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/SenderOptions.java
@@ -23,7 +23,7 @@
 /**
  * Options that control the behavior of a {@link Sender} created from them.
  */
-public class SenderOptions extends LinkOptions<SenderOptions>{
+public class SenderOptions extends LinkOptions<SenderOptions> implements Cloneable {
 
     private long sendTimeout = ConnectionOptions.DEFAULT_SEND_TIMEOUT;
 
@@ -97,14 +97,14 @@
      * @param other
      *      the target of this copy operation.
      *
-     * @return this options class for chaining.
+     * @return the {@link SenderOptions} instance that was given.
      */
     protected SenderOptions copyInto(SenderOptions other) {
         super.copyInto(other);
 
         other.sendTimeout(sendTimeout);
 
-        return this;
+        return other;
     }
 
     @Override
diff --git a/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/SessionOptions.java b/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/SessionOptions.java
index dac19d5..55cfb71 100644
--- a/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/SessionOptions.java
+++ b/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/SessionOptions.java
@@ -27,7 +27,7 @@
 /**
  * Options that control the behavior of the {@link Session} created from them.
  */
-public class SessionOptions {
+public class SessionOptions implements Cloneable {
 
     /**
      * The default Session configured incoming capacity limit to provide to the remote
@@ -83,7 +83,7 @@
      * @param other
      *      the target of this copy operation.
      *
-     * @return this options class for chaining.
+     * @return the {@link SessionOptions} instance that was given.
      */
     protected SessionOptions copyInto(SessionOptions other) {
         other.closeTimeout(closeTimeout);
@@ -105,7 +105,7 @@
             other.properties(new HashMap<>(properties));
         }
 
-        return this;
+        return other;
     }
 
     /**
diff --git a/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/SourceOptions.java b/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/SourceOptions.java
index c9005c2..51def8a 100644
--- a/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/SourceOptions.java
+++ b/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/SourceOptions.java
@@ -25,7 +25,7 @@
 /**
  * Options type that carries configuration for link Source types.
  */
-public final class SourceOptions extends TerminusOptions<SourceOptions> {
+public final class SourceOptions extends TerminusOptions<SourceOptions> implements Cloneable {
 
     private static final DeliveryState.Type[] DEFAULT_OUTCOMES = new DeliveryState.Type[] {
         DeliveryState.Type.ACCEPTED, DeliveryState.Type.REJECTED, DeliveryState.Type.RELEASED, DeliveryState.Type.MODIFIED
@@ -55,14 +55,14 @@
      *
      * @return this {@link SourceOptions} instance.
      */
-    public SourceOptions copyInto(SourceOptions other) {
+    protected SourceOptions copyInto(SourceOptions other) {
         super.copyInto(other);
         other.distributionMode(distributionMode);
         if (filters != null) {
             other.filters(new HashMap<>(filters));
         }
 
-        return this;
+        return other;
     }
 
     /**
diff --git a/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/SslOptions.java b/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/SslOptions.java
index 144f870..5ef0f37 100644
--- a/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/SslOptions.java
+++ b/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/SslOptions.java
@@ -425,7 +425,7 @@
      *
      * @return the options instance that was copied into.
      */
-    public SslOptions copyInto(SslOptions other) {
+    protected SslOptions copyInto(SslOptions other) {
         other.sslEnabled(sslEnabled());
         other.keyStoreLocation(keyStoreLocation());
         other.keyStorePassword(keyStorePassword());
diff --git a/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/StreamReceiverOptions.java b/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/StreamReceiverOptions.java
index 3d52fec..90f0471 100644
--- a/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/StreamReceiverOptions.java
+++ b/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/StreamReceiverOptions.java
@@ -22,7 +22,7 @@
  * Options class that controls various aspects of a {@link StreamReceiver} instance and how
  * a streamed message transfer is written.
  */
-public class StreamReceiverOptions extends LinkOptions<StreamReceiverOptions> {
+public final class StreamReceiverOptions extends LinkOptions<StreamReceiverOptions> implements Cloneable {
 
     /**
      * Defines the default read buffering size which is used to control how much incoming
@@ -67,7 +67,7 @@
      * @param other
      *      the target of this copy operation.
      *
-     * @return this {@link StreamReceiverOptions} class for chaining.
+     * @return the {@link StreamReceiverOptions} instance that was given.
      */
     protected StreamReceiverOptions copyInto(StreamReceiverOptions other) {
         super.copyInto(other);
@@ -77,7 +77,7 @@
         other.creditWindow(creditWindow);
         other.drainTimeout(drainTimeout);
 
-        return this;
+        return other;
     }
 
     /**
diff --git a/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/StreamSenderOptions.java b/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/StreamSenderOptions.java
index a519b2e..4040ef5 100644
--- a/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/StreamSenderOptions.java
+++ b/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/StreamSenderOptions.java
@@ -24,7 +24,7 @@
  * Options class that controls various aspects of a {@link StreamSenderMessage} instance and how
  * a streamed message transfer is written.
  */
-public class StreamSenderOptions extends LinkOptions<StreamSenderOptions> {
+public class StreamSenderOptions extends LinkOptions<StreamSenderOptions> implements Cloneable {
 
     /**
      * Defines the default pending write buffering size which is used to control how much outgoing
@@ -76,7 +76,7 @@
      * @param other
      *      the target of this copy operation.
      *
-     * @return this {@link StreamSenderOptions} class for chaining.
+     * @return the {@link StreamSenderOptions} instance that was given.
      */
     protected StreamSenderOptions copyInto(StreamSenderOptions other) {
         super.copyInto(other);
@@ -85,7 +85,7 @@
         other.sendTimeout(sendTimeout);
         other.pendingWritesBufferSize(pendingWritesBufferSize);
 
-        return this;
+        return other;
     }
 
     /**
diff --git a/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/TargetOptions.java b/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/TargetOptions.java
index 7ab40f7..37724db 100644
--- a/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/TargetOptions.java
+++ b/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/TargetOptions.java
@@ -19,7 +19,7 @@
 /**
  * Options type that carries configuration for link Target types.
  */
-public final class TargetOptions extends TerminusOptions<TargetOptions> {
+public final class TargetOptions extends TerminusOptions<TargetOptions> implements Cloneable {
 
     /**
      * @param other
@@ -27,9 +27,9 @@
      *
      * @return the given {@link TargetOptions} instance with all configuration copied from this instance.
      */
-    public TargetOptions copyInto(TargetOptions other) {
+    protected TargetOptions copyInto(TargetOptions other) {
         super.copyInto(other);
-        return this;
+        return other;
     }
 
     @Override
diff --git a/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/ClientOptionsTest.java b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/ClientOptionsTest.java
new file mode 100644
index 0000000..eb8ba88
--- /dev/null
+++ b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/ClientOptionsTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.qpid.protonj2.client;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import org.junit.jupiter.api.Test;
+
+public class ClientOptionsTest {
+
+    @Test
+    void testCreate() {
+        ClientOptions options = new ClientOptions();
+
+        assertNull(options.id());
+        assertNull(options.futureType());
+    }
+
+    @Test
+    void testCopy() {
+        ClientOptions options = new ClientOptions();
+
+        options.id("test");
+        options.futureType("past-present");
+
+        ClientOptions copy = options.clone();
+
+        assertNotSame(copy, options);
+        assertEquals(options.id(), copy.id());
+        assertEquals(options.futureType(), copy.futureType());
+    }
+}
diff --git a/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/ConnectionOptionsTest.java b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/ConnectionOptionsTest.java
new file mode 100644
index 0000000..34eef53
--- /dev/null
+++ b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/ConnectionOptionsTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.qpid.protonj2.client;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import org.junit.jupiter.api.Test;
+
+public class ConnectionOptionsTest {
+
+    @Test
+    void testCreate() {
+        ConnectionOptions options = new ConnectionOptions();
+
+        assertNull(options.password());
+        assertNull(options.user());
+    }
+
+    @Test
+    void testCopy() {
+        ConnectionOptions options = new ConnectionOptions();
+
+        options.user("test");
+        options.password("test-pass");
+
+        ConnectionOptions copy = options.clone();
+
+        assertNotSame(copy, options);
+        assertEquals(options.user(), copy.user());
+        assertEquals(options.password(), copy.password());
+    }
+}
diff --git a/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/RecconnectOptionsTest.java b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/RecconnectOptionsTest.java
new file mode 100644
index 0000000..6a8ee93
--- /dev/null
+++ b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/RecconnectOptionsTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.qpid.protonj2.client;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import org.junit.jupiter.api.Test;
+
+public class RecconnectOptionsTest {
+
+    @Test
+    void testCreate() {
+        ConnectionOptions options = new ConnectionOptions();
+
+        assertNull(options.password());
+        assertNull(options.user());
+    }
+
+    @Test
+    void testCopy() {
+        ConnectionOptions options = new ConnectionOptions();
+
+        options.user("test");
+        options.password("test-pass");
+
+        ConnectionOptions copy = options.clone();
+
+        assertNotSame(copy, options);
+        assertEquals(options.user(), copy.user());
+        assertEquals(options.password(), copy.password());
+    }
+}
diff --git a/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/ReceiverOptionsTest.java b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/ReceiverOptionsTest.java
new file mode 100644
index 0000000..df9b50c
--- /dev/null
+++ b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/ReceiverOptionsTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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.qpid.protonj2.client;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+public class ReceiverOptionsTest {
+
+    @Test
+    void testCreate() {
+        ReconnectOptions options = new ReconnectOptions();
+
+        assertNotNull(options.reconnectLocations());
+        assertTrue(options.reconnectLocations().isEmpty());
+        assertFalse(options.reconnectEnabled());
+    }
+
+    @Test
+    void testCopy() {
+        ReconnectOptions options = new ReconnectOptions();
+
+        options.addReconnectLocation("test1", 5672);
+        options.reconnectEnabled(true);
+
+        ReconnectOptions copy = options.clone();
+
+        assertNotSame(copy, options);
+        assertEquals(options.reconnectLocations(), copy.reconnectLocations());
+        assertEquals(options.reconnectEnabled(), copy.reconnectEnabled());
+    }
+}
diff --git a/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/SaslOptionsTest.java b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/SaslOptionsTest.java
index ff3a5e2..39f9a42 100644
--- a/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/SaslOptionsTest.java
+++ b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/SaslOptionsTest.java
@@ -19,6 +19,7 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import org.junit.jupiter.api.Test;
@@ -44,6 +45,7 @@
 
         SaslOptions copy = options.clone();
 
+        assertNotSame(copy, options);
         assertEquals(options.allowedMechanisms(), copy.allowedMechanisms());
         assertEquals(options.saslEnabled(), copy.saslEnabled());
     }
diff --git a/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/SenderOptionsTest.java b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/SenderOptionsTest.java
new file mode 100644
index 0000000..7f31488
--- /dev/null
+++ b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/SenderOptionsTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.qpid.protonj2.client;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import org.junit.jupiter.api.Test;
+
+public class SenderOptionsTest {
+
+    @Test
+    void testCreate() {
+        SenderOptions options = new SenderOptions();
+
+        assertNull(options.offeredCapabilities());
+        assertNull(options.desiredCapabilities());
+    }
+
+    @Test
+    void testCopy() {
+        SenderOptions options = new SenderOptions();
+
+        options.offeredCapabilities("test1");
+        options.desiredCapabilities("test2");
+
+        SenderOptions copy = options.clone();
+
+        assertNotSame(copy, options);
+        assertArrayEquals(options.offeredCapabilities(), copy.offeredCapabilities());
+        assertArrayEquals(options.desiredCapabilities(), copy.desiredCapabilities());
+    }
+}
diff --git a/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/SessionOptionsTest.java b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/SessionOptionsTest.java
new file mode 100644
index 0000000..96dc450
--- /dev/null
+++ b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/SessionOptionsTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.qpid.protonj2.client;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import org.junit.jupiter.api.Test;
+
+public class SessionOptionsTest {
+
+    @Test
+    void testCreate() {
+        SessionOptions options = new SessionOptions();
+
+        assertNull(options.offeredCapabilities());
+        assertNull(options.desiredCapabilities());
+    }
+
+    @Test
+    void testCopy() {
+        SessionOptions options = new SessionOptions();
+
+        options.offeredCapabilities("test1");
+        options.desiredCapabilities("test2");
+
+        SessionOptions copy = options.clone();
+
+        assertNotSame(copy, options);
+        assertArrayEquals(options.offeredCapabilities(), copy.offeredCapabilities());
+        assertArrayEquals(options.desiredCapabilities(), copy.desiredCapabilities());
+    }
+}
diff --git a/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/SourceOptionsTest.java b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/SourceOptionsTest.java
new file mode 100644
index 0000000..d56932d
--- /dev/null
+++ b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/SourceOptionsTest.java
@@ -0,0 +1,45 @@
+/*
+ * 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.qpid.protonj2.client;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import org.junit.jupiter.api.Test;
+
+public class SourceOptionsTest {
+
+    @Test
+    void testCreate() {
+        SourceOptions options = new SourceOptions();
+
+        assertNull(options.capabilities());
+    }
+
+    @Test
+    void testCopy() {
+        SourceOptions options = new SourceOptions();
+
+        options.capabilities("test1");
+
+        SourceOptions copy = options.clone();
+
+        assertNotSame(copy, options);
+        assertArrayEquals(options.capabilities(), copy.capabilities());
+    }
+}
diff --git a/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/SslOptionsTest.java b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/SslOptionsTest.java
index 1f7fbf6..4c62969 100644
--- a/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/SslOptionsTest.java
+++ b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/SslOptionsTest.java
@@ -20,6 +20,7 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
@@ -99,8 +100,10 @@
 
     @Test
     public void testClone() {
-        SslOptions options = createNonDefaultOptions().clone();
+        SslOptions original = createNonDefaultOptions();
+        SslOptions options = original.clone();
 
+        assertNotSame(original, options);
         assertTrue(options.sslEnabled());
         assertEquals(TEST_DEFAULT_SSL_PORT, options.defaultSslPort());
         assertEquals(CLIENT_KEYSTORE, options.keyStoreLocation());
diff --git a/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/StreamReceiverOptionsTest.java b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/StreamReceiverOptionsTest.java
new file mode 100644
index 0000000..f02e249
--- /dev/null
+++ b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/StreamReceiverOptionsTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.qpid.protonj2.client;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import org.junit.jupiter.api.Test;
+
+public class StreamReceiverOptionsTest {
+
+    @Test
+    void testCreate() {
+        StreamReceiverOptions options = new StreamReceiverOptions();
+
+        assertNull(options.offeredCapabilities());
+        assertNull(options.desiredCapabilities());
+    }
+
+    @Test
+    void testCopy() {
+        StreamReceiverOptions options = new StreamReceiverOptions();
+
+        options.offeredCapabilities("test1");
+        options.desiredCapabilities("test2");
+
+        StreamReceiverOptions copy = options.clone();
+
+        assertNotSame(copy, options);
+        assertArrayEquals(options.offeredCapabilities(), copy.offeredCapabilities());
+        assertArrayEquals(options.desiredCapabilities(), copy.desiredCapabilities());
+    }
+}
diff --git a/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/StreamSenderOptionsTest.java b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/StreamSenderOptionsTest.java
new file mode 100644
index 0000000..c34064d
--- /dev/null
+++ b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/StreamSenderOptionsTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.qpid.protonj2.client;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import org.junit.jupiter.api.Test;
+
+public class StreamSenderOptionsTest {
+
+    @Test
+    void testCreate() {
+        StreamSenderOptions options = new StreamSenderOptions();
+
+        assertNull(options.offeredCapabilities());
+        assertNull(options.desiredCapabilities());
+    }
+
+    @Test
+    void testCopy() {
+        StreamSenderOptions options = new StreamSenderOptions();
+
+        options.offeredCapabilities("test1");
+        options.desiredCapabilities("test2");
+
+        StreamSenderOptions copy = options.clone();
+
+        assertNotSame(copy, options);
+        assertArrayEquals(options.offeredCapabilities(), copy.offeredCapabilities());
+        assertArrayEquals(options.desiredCapabilities(), copy.desiredCapabilities());
+    }
+}
diff --git a/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/TargetOptionsTest.java b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/TargetOptionsTest.java
new file mode 100644
index 0000000..0a5c2a5
--- /dev/null
+++ b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/TargetOptionsTest.java
@@ -0,0 +1,45 @@
+/*
+ * 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.qpid.protonj2.client;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import org.junit.jupiter.api.Test;
+
+public class TargetOptionsTest {
+
+    @Test
+    void testCreate() {
+        TargetOptions options = new TargetOptions();
+
+        assertNull(options.capabilities());
+    }
+
+    @Test
+    void testCopy() {
+        TargetOptions options = new TargetOptions();
+
+        options.capabilities("test1");
+
+        TargetOptions copy = options.clone();
+
+        assertNotSame(copy, options);
+        assertArrayEquals(options.capabilities(), copy.capabilities());
+    }
+}
diff --git a/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/TransportOptionsTest.java b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/TransportOptionsTest.java
index 6fd93b2..b4d30af 100644
--- a/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/TransportOptionsTest.java
+++ b/protonj2-client/src/test/java/org/apache/qpid/protonj2/client/TransportOptionsTest.java
@@ -20,6 +20,7 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
@@ -82,7 +83,10 @@
 
     @Test
     public void testClone() {
-        TransportOptions options = createNonDefaultOptions().clone();
+        TransportOptions original = createNonDefaultOptions();
+        TransportOptions options = original.clone();
+
+        assertNotSame(original, options);
 
         assertEquals(TEST_SEND_BUFFER_SIZE, options.sendBufferSize());
         assertEquals(TEST_RECEIVE_BUFFER_SIZE, options.receiveBufferSize());