From d81c4ea9ec82c279c48edf033d4303f07c6b180b Mon Sep 17 00:00:00 2001 From: Szymon Sasin Date: Mon, 22 Apr 2024 16:21:43 +0300 Subject: [PATCH 1/2] GH-82 TransportContext: merge and key iterator --- .../com/mbed/coap/packet/CoapRequest.java | 5 ++ .../mbed/coap/transport/TransportContext.java | 39 +++++++++++- .../com/mbed/coap/packet/CoapRequestTest.java | 5 +- .../coap/transport/TransportContextTest.java | 60 ++++++++++++++++++- 4 files changed, 103 insertions(+), 6 deletions(-) diff --git a/coap-core/src/main/java/com/mbed/coap/packet/CoapRequest.java b/coap-core/src/main/java/com/mbed/coap/packet/CoapRequest.java index 35411d1e..847ae841 100644 --- a/coap-core/src/main/java/com/mbed/coap/packet/CoapRequest.java +++ b/coap-core/src/main/java/com/mbed/coap/packet/CoapRequest.java @@ -279,6 +279,11 @@ public Builder addContext(TransportContext.Key key, T value) { return this; } + public Builder addContext(TransportContext context) { + transContext = transContext.with(context); + return this; + } + public Builder address(InetSocketAddress address) { this.peerAddress = address; return this; diff --git a/coap-core/src/main/java/com/mbed/coap/transport/TransportContext.java b/coap-core/src/main/java/com/mbed/coap/transport/TransportContext.java index 103dc1c5..ebf70ff0 100644 --- a/coap-core/src/main/java/com/mbed/coap/transport/TransportContext.java +++ b/coap-core/src/main/java/com/mbed/coap/transport/TransportContext.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 java-coap contributors (https://github.com/open-coap/java-coap) + * Copyright (C) 2022-2024 java-coap contributors (https://github.com/open-coap/java-coap) * SPDX-License-Identifier: Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +17,11 @@ import static java.util.Objects.requireNonNull; import java.time.Duration; +import java.util.Iterator; +import java.util.NoSuchElementException; import java.util.Objects; -public final class TransportContext { +public final class TransportContext implements Iterable> { private final Key key; private final Object value; @@ -66,6 +68,17 @@ public TransportContext with(Key key, T value) { return new TransportContext(requireNonNull(key), requireNonNull(value), this); } + public TransportContext with(TransportContext otherCtx) { + if (otherCtx.equals(EMPTY)) { + return this; + } + TransportContext mergedContext = this.with(otherCtx.key, otherCtx.value); + if (otherCtx.next == null) { + return mergedContext; + } + return mergedContext.with(otherCtx.next); + } + @Override public boolean equals(Object o) { if (this == o) { @@ -83,6 +96,28 @@ public int hashCode() { return Objects.hash(key, value, next); } + @Override + public Iterator> iterator() { + return new Iterator>() { + private TransportContext current = TransportContext.this; + + @Override + public boolean hasNext() { + return current != null; + } + + @Override + public Key next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + Key key = current.key; + current = current.next; + return key; + } + }; + } + public static final class Key { private final T defaultValue; diff --git a/coap-core/src/test/java/com/mbed/coap/packet/CoapRequestTest.java b/coap-core/src/test/java/com/mbed/coap/packet/CoapRequestTest.java index 73f96367..69096287 100644 --- a/coap-core/src/test/java/com/mbed/coap/packet/CoapRequestTest.java +++ b/coap-core/src/test/java/com/mbed/coap/packet/CoapRequestTest.java @@ -26,6 +26,7 @@ import static com.mbed.coap.packet.MediaTypes.CT_APPLICATION_JSON; import static com.mbed.coap.packet.Opaque.EMPTY; import static com.mbed.coap.packet.Opaque.decodeHex; +import static com.mbed.coap.transport.TransportContext.NON_CONFIRMABLE; import static com.mbed.coap.transport.TransportContext.RESPONSE_TIMEOUT; import static java.time.Duration.ofSeconds; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -96,11 +97,13 @@ void shouldModifyTransportContext() { // when CoapRequest request2 = request.modify() - .addContext(DUMMY_KEY, "test") + .addContext(NON_CONFIRMABLE, true) + .addContext(TransportContext.of(DUMMY_KEY, "test")) .build(); // then assertEquals("test", request2.getTransContext(DUMMY_KEY)); + assertEquals(true, request2.getTransContext(NON_CONFIRMABLE)); } @Test diff --git a/coap-core/src/test/java/com/mbed/coap/transport/TransportContextTest.java b/coap-core/src/test/java/com/mbed/coap/transport/TransportContextTest.java index d57d3de8..322807ee 100644 --- a/coap-core/src/test/java/com/mbed/coap/transport/TransportContextTest.java +++ b/coap-core/src/test/java/com/mbed/coap/transport/TransportContextTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 java-coap contributors (https://github.com/open-coap/java-coap) + * Copyright (C) 2022-2024 java-coap contributors (https://github.com/open-coap/java-coap) * SPDX-License-Identifier: Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,8 +15,14 @@ */ package com.mbed.coap.transport; +import static com.mbed.coap.transport.TransportContext.EMPTY; 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.Iterator; +import java.util.NoSuchElementException; import nl.jqno.equalsverifier.EqualsVerifier; import nl.jqno.equalsverifier.Warning; import org.junit.jupiter.api.Test; @@ -38,12 +44,60 @@ void test() { assertEquals("afds", trans.get(DUMMY_KEY2)); } + @Test + void merge() { + TransportContext ctx1 = TransportContext.of(DUMMY_KEY, "111"); + TransportContext ctx2 = TransportContext.of(DUMMY_KEY2, "222"); + + TransportContext ctx3 = ctx1.with(ctx2); + + assertEquals("111", ctx3.get(DUMMY_KEY)); + assertEquals("222", ctx3.get(DUMMY_KEY2)); + } + + @Test + void mergeWithEmpty() { + TransportContext ctx1 = TransportContext.of(DUMMY_KEY, "111"); + + assertEquals(ctx1, ctx1.with(EMPTY)); + assertEquals(ctx1, EMPTY.with(ctx1)); + } + + @Test + void mergeAndOverWrite() { + TransportContext ctx1 = TransportContext.of(DUMMY_KEY, "111").with(DUMMY_KEY2, "222"); + TransportContext ctx2 = TransportContext.of(DUMMY_KEY, "aaa"); + + TransportContext ctx3 = ctx1.with(ctx2); + + assertEquals("aaa", ctx3.get(DUMMY_KEY)); + assertEquals("222", ctx3.get(DUMMY_KEY2)); + } + + @Test + void listKeys() { + TransportContext ctx1 = TransportContext.of(DUMMY_KEY, "111").with(DUMMY_KEY2, "222"); + + Iterator> iterator = ctx1.iterator(); + + assertTrue(iterator.hasNext()); + assertEquals(DUMMY_KEY2, iterator.next()); + + assertTrue(iterator.hasNext()); + assertEquals(DUMMY_KEY, iterator.next()); + + assertFalse(iterator.hasNext()); + assertThrows(NoSuchElementException.class, iterator::next); + } + @Test void empty() { - TransportContext trans = TransportContext.EMPTY; + TransportContext trans = EMPTY; assertNull(trans.get(DUMMY_KEY)); assertEquals("default-val", trans.getOrDefault(DUMMY_KEY2, "default-val")); assertEquals("na", trans.get(DUMMY_KEY2)); + + assertEquals(EMPTY, EMPTY.with(EMPTY)); } @Test @@ -51,7 +105,7 @@ public void equalsAndHashTest() throws Exception { EqualsVerifier.forClass(TransportContext.class) .suppress(Warning.NONFINAL_FIELDS) .usingGetClass() - .withPrefabValues(TransportContext.class, TransportContext.EMPTY, TransportContext.of(TransportContext.NON_CONFIRMABLE, true)) + .withPrefabValues(TransportContext.class, EMPTY, TransportContext.of(TransportContext.NON_CONFIRMABLE, true)) .verify(); } From 0d782084713f68ea61b0c2971f88f5761ffddbae Mon Sep 17 00:00:00 2001 From: Szymon Sasin Date: Wed, 10 Jul 2024 19:49:40 +0300 Subject: [PATCH 2/2] fix --- .../mbed/coap/transport/TransportContext.java | 54 +++++-------------- .../coap/transport/TransportContextTest.java | 39 +++++++------- 2 files changed, 32 insertions(+), 61 deletions(-) diff --git a/coap-core/src/main/java/com/mbed/coap/transport/TransportContext.java b/coap-core/src/main/java/com/mbed/coap/transport/TransportContext.java index ebf70ff0..f01e18b7 100644 --- a/coap-core/src/main/java/com/mbed/coap/transport/TransportContext.java +++ b/coap-core/src/main/java/com/mbed/coap/transport/TransportContext.java @@ -17,11 +17,11 @@ import static java.util.Objects.requireNonNull; import java.time.Duration; -import java.util.Iterator; -import java.util.NoSuchElementException; +import java.util.HashSet; import java.util.Objects; +import java.util.Set; -public final class TransportContext implements Iterable> { +public final class TransportContext { private final Key key; private final Object value; @@ -96,26 +96,17 @@ public int hashCode() { return Objects.hash(key, value, next); } - @Override - public Iterator> iterator() { - return new Iterator>() { - private TransportContext current = TransportContext.this; - - @Override - public boolean hasNext() { - return current != null; - } - - @Override - public Key next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - Key key = current.key; - current = current.next; - return key; - } - }; + public Set> keys() { + Set> keys = new HashSet<>(); + addKey(keys); + return keys; + } + + private void addKey(Set> keys) { + keys.add(key); + if (next != null) { + next.addKey(keys); + } } public static final class Key { @@ -124,22 +115,5 @@ public static final class Key { public Key(T defaultValue) { this.defaultValue = defaultValue; } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Key key = (Key) o; - return Objects.equals(defaultValue, key.defaultValue); - } - - @Override - public int hashCode() { - return Objects.hash(defaultValue); - } } } diff --git a/coap-core/src/test/java/com/mbed/coap/transport/TransportContextTest.java b/coap-core/src/test/java/com/mbed/coap/transport/TransportContextTest.java index 322807ee..445be53a 100644 --- a/coap-core/src/test/java/com/mbed/coap/transport/TransportContextTest.java +++ b/coap-core/src/test/java/com/mbed/coap/transport/TransportContextTest.java @@ -16,13 +16,10 @@ package com.mbed.coap.transport; import static com.mbed.coap.transport.TransportContext.EMPTY; +import static org.assertj.core.util.Sets.set; 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.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import java.util.Iterator; -import java.util.NoSuchElementException; import nl.jqno.equalsverifier.EqualsVerifier; import nl.jqno.equalsverifier.Warning; import org.junit.jupiter.api.Test; @@ -32,6 +29,7 @@ public class TransportContextTest { private TransportContext.Key DUMMY_KEY = new TransportContext.Key<>(null); private TransportContext.Key DUMMY_KEY2 = new TransportContext.Key<>("na"); + private TransportContext.Key DUMMY_KEY3 = new TransportContext.Key<>(null); @Test void test() { @@ -53,6 +51,7 @@ void merge() { assertEquals("111", ctx3.get(DUMMY_KEY)); assertEquals("222", ctx3.get(DUMMY_KEY2)); + assertEquals(set(DUMMY_KEY, DUMMY_KEY2), ctx3.keys()); } @Test @@ -61,33 +60,21 @@ void mergeWithEmpty() { assertEquals(ctx1, ctx1.with(EMPTY)); assertEquals(ctx1, EMPTY.with(ctx1)); + assertEquals(set(DUMMY_KEY), ctx1.keys()); } @Test void mergeAndOverWrite() { TransportContext ctx1 = TransportContext.of(DUMMY_KEY, "111").with(DUMMY_KEY2, "222"); - TransportContext ctx2 = TransportContext.of(DUMMY_KEY, "aaa"); + TransportContext ctx2 = TransportContext.of(DUMMY_KEY, "aaa").with(DUMMY_KEY3, "333"); TransportContext ctx3 = ctx1.with(ctx2); assertEquals("aaa", ctx3.get(DUMMY_KEY)); assertEquals("222", ctx3.get(DUMMY_KEY2)); - } - - @Test - void listKeys() { - TransportContext ctx1 = TransportContext.of(DUMMY_KEY, "111").with(DUMMY_KEY2, "222"); - - Iterator> iterator = ctx1.iterator(); - - assertTrue(iterator.hasNext()); - assertEquals(DUMMY_KEY2, iterator.next()); + assertEquals("333", ctx3.get(DUMMY_KEY3)); - assertTrue(iterator.hasNext()); - assertEquals(DUMMY_KEY, iterator.next()); - - assertFalse(iterator.hasNext()); - assertThrows(NoSuchElementException.class, iterator::next); + assertEquals(set(DUMMY_KEY, DUMMY_KEY2, DUMMY_KEY3), ctx3.keys()); } @Test @@ -109,4 +96,14 @@ public void equalsAndHashTest() throws Exception { .verify(); } + @Test + public void equalsAndHashKeys() { + assertEquals(DUMMY_KEY, DUMMY_KEY); + + assertNotEquals(DUMMY_KEY, DUMMY_KEY2); + assertNotEquals(DUMMY_KEY, DUMMY_KEY3); + + assertNotEquals(new TransportContext.Key(null), new TransportContext.Key(null)); + } + }