Skip to content

Commit 0ae2f65

Browse files
apappascschedim
authored andcommitted
feat: Add equals, hashCode, deep copy, and tests to OCICohereChatOptions (spring-projects#2361)
This commit enhances OCICohereChatOptions by: - Updating equals and hashCode methods for proper object comparison. - Updating copy() method, creating new instances of mutable collections (List, Set, Map, Metadata) to prevent shared state. - Adding OCICohereChatOptionsTests to verify copy(), builders, setters, and default values. Signed-off-by: Alexandros Pappas <apappascs@gmail.com>
1 parent aa9ae31 commit 0ae2f65

File tree

2 files changed

+167
-4
lines changed

2 files changed

+167
-4
lines changed

models/spring-ai-oci-genai/src/main/java/org/springframework/ai/oci/cohere/OCICohereChatOptions.java

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023-2024 the original author or authors.
2+
* Copyright 2023-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,7 +16,9 @@
1616

1717
package org.springframework.ai.oci.cohere;
1818

19+
import java.util.ArrayList;
1920
import java.util.List;
21+
import java.util.Objects;
2022

2123
import com.fasterxml.jackson.annotation.JsonInclude;
2224
import com.fasterxml.jackson.annotation.JsonProperty;
@@ -29,6 +31,7 @@
2931
*
3032
* @author Anders Swanson
3133
* @author Ilayaperumal Gopinathan
34+
* @author Alexnadros Pappas
3235
*/
3336
@JsonInclude(JsonInclude.Include.NON_NULL)
3437
public class OCICohereChatOptions implements ChatOptions {
@@ -124,11 +127,11 @@ public static OCICohereChatOptions fromOptions(OCICohereChatOptions fromOptions)
124127
.temperature(fromOptions.temperature)
125128
.topP(fromOptions.topP)
126129
.topK(fromOptions.topK)
127-
.stop(fromOptions.stop)
130+
.stop(fromOptions.stop != null ? new ArrayList<>(fromOptions.stop) : null)
128131
.frequencyPenalty(fromOptions.frequencyPenalty)
129132
.presencePenalty(fromOptions.presencePenalty)
130-
.documents(fromOptions.documents)
131-
.tools(fromOptions.tools)
133+
.documents(fromOptions.documents != null ? new ArrayList<>(fromOptions.documents) : null)
134+
.tools(fromOptions.tools != null ? new ArrayList<>(fromOptions.tools) : null)
132135
.build();
133136
}
134137

@@ -257,10 +260,37 @@ public Double getTopP() {
257260
}
258261

259262
@Override
263+
@SuppressWarnings("unchecked")
260264
public ChatOptions copy() {
261265
return fromOptions(this);
262266
}
263267

268+
@Override
269+
public int hashCode() {
270+
return Objects.hash(model, maxTokens, compartment, servingMode, preambleOverride, temperature, topP, topK, stop,
271+
frequencyPenalty, presencePenalty, documents, tools);
272+
}
273+
274+
@Override
275+
public boolean equals(Object o) {
276+
if (this == o)
277+
return true;
278+
if (o == null || getClass() != o.getClass())
279+
return false;
280+
281+
OCICohereChatOptions that = (OCICohereChatOptions) o;
282+
283+
return Objects.equals(this.model, that.model) && Objects.equals(this.maxTokens, that.maxTokens)
284+
&& Objects.equals(this.compartment, that.compartment)
285+
&& Objects.equals(this.servingMode, that.servingMode)
286+
&& Objects.equals(this.preambleOverride, that.preambleOverride)
287+
&& Objects.equals(this.temperature, that.temperature) && Objects.equals(this.topP, that.topP)
288+
&& Objects.equals(this.topK, that.topK) && Objects.equals(this.stop, that.stop)
289+
&& Objects.equals(this.frequencyPenalty, that.frequencyPenalty)
290+
&& Objects.equals(this.presencePenalty, that.presencePenalty)
291+
&& Objects.equals(this.documents, that.documents) && Objects.equals(this.tools, that.tools);
292+
}
293+
264294
public static class Builder {
265295

266296
protected OCICohereChatOptions chatOptions;
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
* Copyright 2025-2025 the original author or authors.
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+
* https://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+
17+
package org.springframework.ai.oci.cohere;
18+
19+
import com.oracle.bmc.generativeaiinference.model.CohereTool;
20+
import org.junit.jupiter.api.Test;
21+
22+
import java.util.List;
23+
import java.util.Map;
24+
25+
import static org.assertj.core.api.Assertions.assertThat;
26+
27+
/**
28+
* Tests for {@link OCICohereChatOptions}.
29+
*
30+
* @author Alexandros Pappas
31+
*/
32+
class OCICohereChatOptionsTests {
33+
34+
@Test
35+
void testBuilderWithAllFields() {
36+
OCICohereChatOptions options = OCICohereChatOptions.builder()
37+
.model("test-model")
38+
.maxTokens(10)
39+
.compartment("test-compartment")
40+
.servingMode("test-servingMode")
41+
.preambleOverride("test-preambleOverride")
42+
.temperature(0.6)
43+
.topP(0.6)
44+
.topK(50)
45+
.stop(List.of("test"))
46+
.frequencyPenalty(0.5)
47+
.presencePenalty(0.5)
48+
.documents(List.of("doc1", "doc2"))
49+
.build();
50+
51+
assertThat(options)
52+
.extracting("model", "maxTokens", "compartment", "servingMode", "preambleOverride", "temperature", "topP",
53+
"topK", "stop", "frequencyPenalty", "presencePenalty", "documents")
54+
.containsExactly("test-model", 10, "test-compartment", "test-servingMode", "test-preambleOverride", 0.6,
55+
0.6, 50, List.of("test"), 0.5, 0.5, List.of("doc1", "doc2"));
56+
}
57+
58+
@Test
59+
void testCopy() {
60+
OCICohereChatOptions original = OCICohereChatOptions.builder()
61+
.model("test-model")
62+
.maxTokens(10)
63+
.compartment("test-compartment")
64+
.servingMode("test-servingMode")
65+
.preambleOverride("test-preambleOverride")
66+
.temperature(0.6)
67+
.topP(0.6)
68+
.topK(50)
69+
.stop(List.of("test"))
70+
.frequencyPenalty(0.5)
71+
.presencePenalty(0.5)
72+
.documents(List.of("doc1", "doc2"))
73+
.tools(List.of(new CohereTool("test-tool", "test-context", Map.of())))
74+
.build();
75+
76+
OCICohereChatOptions copied = (OCICohereChatOptions) original.copy();
77+
78+
assertThat(copied).isNotSameAs(original).isEqualTo(original);
79+
// Ensure deep copy
80+
assertThat(copied.getStop()).isNotSameAs(original.getStop());
81+
assertThat(copied.getDocuments()).isNotSameAs(original.getDocuments());
82+
assertThat(copied.getTools()).isNotSameAs(original.getTools());
83+
}
84+
85+
@Test
86+
void testSetters() {
87+
OCICohereChatOptions options = new OCICohereChatOptions();
88+
options.setModel("test-model");
89+
options.setMaxTokens(10);
90+
options.setCompartment("test-compartment");
91+
options.setServingMode("test-servingMode");
92+
options.setPreambleOverride("test-preambleOverride");
93+
options.setTemperature(0.6);
94+
options.setTopP(0.6);
95+
options.setTopK(50);
96+
options.setStop(List.of("test"));
97+
options.setFrequencyPenalty(0.5);
98+
options.setPresencePenalty(0.5);
99+
options.setDocuments(List.of("doc1", "doc2"));
100+
101+
assertThat(options.getModel()).isEqualTo("test-model");
102+
assertThat(options.getMaxTokens()).isEqualTo(10);
103+
assertThat(options.getCompartment()).isEqualTo("test-compartment");
104+
assertThat(options.getServingMode()).isEqualTo("test-servingMode");
105+
assertThat(options.getPreambleOverride()).isEqualTo("test-preambleOverride");
106+
assertThat(options.getTemperature()).isEqualTo(0.6);
107+
assertThat(options.getTopP()).isEqualTo(0.6);
108+
assertThat(options.getTopK()).isEqualTo(50);
109+
assertThat(options.getStop()).isEqualTo(List.of("test"));
110+
assertThat(options.getFrequencyPenalty()).isEqualTo(0.5);
111+
assertThat(options.getPresencePenalty()).isEqualTo(0.5);
112+
assertThat(options.getDocuments()).isEqualTo(List.of("doc1", "doc2"));
113+
}
114+
115+
@Test
116+
void testDefaultValues() {
117+
OCICohereChatOptions options = new OCICohereChatOptions();
118+
assertThat(options.getModel()).isNull();
119+
assertThat(options.getMaxTokens()).isNull();
120+
assertThat(options.getCompartment()).isNull();
121+
assertThat(options.getServingMode()).isNull();
122+
assertThat(options.getPreambleOverride()).isNull();
123+
assertThat(options.getTemperature()).isNull();
124+
assertThat(options.getTopP()).isNull();
125+
assertThat(options.getTopK()).isNull();
126+
assertThat(options.getStop()).isNull();
127+
assertThat(options.getFrequencyPenalty()).isNull();
128+
assertThat(options.getPresencePenalty()).isNull();
129+
assertThat(options.getDocuments()).isNull();
130+
assertThat(options.getTools()).isNull();
131+
}
132+
133+
}

0 commit comments

Comments
 (0)