Skip to content

Commit 0f74e08

Browse files
Merge pull request #112 from oracle-samples/binary_double_test
Add Binary Double datatype tests
2 parents dac6778 + bec361e commit 0f74e08

File tree

1 file changed

+365
-0
lines changed

1 file changed

+365
-0
lines changed

tests/binary_double_test.go

Lines changed: 365 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,365 @@
1+
/*
2+
** Copyright (c) 2025 Oracle and/or its affiliates.
3+
**
4+
** The Universal Permissive License (UPL), Version 1.0
5+
**
6+
** Subject to the condition set forth below, permission is hereby granted to any
7+
** person obtaining a copy of this software, associated documentation and/or data
8+
** (collectively the "Software"), free of charge and under any and all copyright
9+
** rights in the Software, and any and all patent rights owned or freely
10+
** licensable by each licensor hereunder covering either (i) the unmodified
11+
** Software as contributed to or provided by such licensor, or (ii) the Larger
12+
** Works (as defined below), to deal in both
13+
**
14+
** (a) the Software, and
15+
** (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
16+
** one is included with the Software (each a "Larger Work" to which the Software
17+
** is contributed by such licensors),
18+
**
19+
** without restriction, including without limitation the rights to copy, create
20+
** derivative works of, display, perform, and distribute the Software and make,
21+
** use, sell, offer for sale, import, export, have made, and have sold the
22+
** Software and the Larger Work(s), and to sublicense the foregoing rights on
23+
** either these or other terms.
24+
**
25+
** This license is subject to the following condition:
26+
** The above copyright notice and either this complete permission notice or at
27+
** a minimum a reference to the UPL must be included in all copies or
28+
** substantial portions of the Software.
29+
**
30+
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31+
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32+
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33+
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34+
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35+
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36+
** SOFTWARE.
37+
*/
38+
39+
package tests
40+
41+
import (
42+
"database/sql"
43+
"math"
44+
"testing"
45+
)
46+
47+
const (
48+
// doubleComparisonEpsilon is used for direct value comparison
49+
doubleComparisonEpsilon = 1e-15
50+
// doubleAggregateEpsilon is used for aggregate operations (SUM, AVG, etc.)
51+
doubleAggregateEpsilon = 1e-10
52+
)
53+
54+
type BinaryDoubleTest struct {
55+
ID uint `gorm:"column:ID;primaryKey"`
56+
DoubleValue float64 `gorm:"column:DOUBLE_VALUE;type:BINARY_DOUBLE"`
57+
NullableDouble *float64 `gorm:"column:NULLABLE_DOUBLE;type:BINARY_DOUBLE"`
58+
SQLNullFloat sql.NullFloat64 `gorm:"column:SQL_NULL_FLOAT;type:BINARY_DOUBLE"`
59+
}
60+
61+
func (BinaryDoubleTest) TableName() string {
62+
return "BINARY_DOUBLE_TESTS"
63+
}
64+
65+
func TestBinaryDoubleBasicCRUD(t *testing.T) {
66+
DB.Migrator().DropTable(&BinaryDoubleTest{})
67+
if err := DB.AutoMigrate(&BinaryDoubleTest{}); err != nil {
68+
t.Fatalf("failed to migrate: %v", err)
69+
}
70+
71+
// CREATE - Insert basic double value
72+
testValue := 3.141592653589793
73+
bd1 := BinaryDoubleTest{DoubleValue: testValue}
74+
if err := DB.Create(&bd1).Error; err != nil {
75+
t.Fatalf("insert failed: %v", err)
76+
}
77+
78+
// READ - Fetch and verify
79+
var got BinaryDoubleTest
80+
if err := DB.First(&got, bd1.ID).Error; err != nil {
81+
t.Fatalf("fetch failed: %v", err)
82+
}
83+
84+
if math.Abs(got.DoubleValue - testValue) > doubleComparisonEpsilon {
85+
t.Errorf("expected %v, got %v", testValue, got.DoubleValue)
86+
}
87+
88+
// UPDATE - Modify the value
89+
newValue := 2.718281828459045
90+
if err := DB.Model(&got).Update("DoubleValue", newValue).Error; err != nil {
91+
t.Fatalf("update failed: %v", err)
92+
}
93+
94+
// Verify update
95+
var updated BinaryDoubleTest
96+
if err := DB.First(&updated, bd1.ID).Error; err != nil {
97+
t.Fatalf("fetch after update failed: %v", err)
98+
}
99+
if math.Abs(updated.DoubleValue - newValue) > doubleComparisonEpsilon {
100+
t.Errorf("expected %v after update, got %v", newValue, updated.DoubleValue)
101+
}
102+
103+
// DELETE
104+
if err := DB.Delete(&updated).Error; err != nil {
105+
t.Fatalf("delete failed: %v", err)
106+
}
107+
108+
// Verify deletion
109+
var deleted BinaryDoubleTest
110+
err := DB.First(&deleted, bd1.ID).Error
111+
if err == nil {
112+
t.Error("expected record to be deleted")
113+
}
114+
}
115+
116+
func TestBinaryDoubleSpecialValues(t *testing.T) {
117+
DB.Migrator().DropTable(&BinaryDoubleTest{})
118+
DB.AutoMigrate(&BinaryDoubleTest{})
119+
120+
testCases := []struct {
121+
name string
122+
value float64
123+
}{
124+
{"Positive Infinity", math.Inf(1)},
125+
{"Negative Infinity", math.Inf(-1)},
126+
{"NaN", math.NaN()},
127+
{"Max Float64", math.MaxFloat64},
128+
{"Min Float64", -math.MaxFloat64},
129+
{"Smallest Positive", math.SmallestNonzeroFloat64},
130+
{"Zero", 0.0},
131+
{"Negative Zero", -0.0},
132+
}
133+
134+
for _, tc := range testCases {
135+
t.Run(tc.name, func(t *testing.T) {
136+
bd := BinaryDoubleTest{DoubleValue: tc.value}
137+
if err := DB.Create(&bd).Error; err != nil {
138+
t.Fatalf("failed to insert %s: %v", tc.name, err)
139+
}
140+
141+
var got BinaryDoubleTest
142+
if err := DB.First(&got, bd.ID).Error; err != nil {
143+
t.Fatalf("failed to fetch %s: %v", tc.name, err)
144+
}
145+
146+
if math.IsNaN(tc.value) {
147+
if !math.IsNaN(got.DoubleValue) {
148+
t.Errorf("expected NaN, got %v", got.DoubleValue)
149+
}
150+
} else if math.IsInf(tc.value, 1) {
151+
if !math.IsInf(got.DoubleValue, 1) {
152+
t.Errorf("expected +Inf, got %v", got.DoubleValue)
153+
}
154+
} else if math.IsInf(tc.value, -1) {
155+
if !math.IsInf(got.DoubleValue, -1) {
156+
t.Errorf("expected -Inf, got %v", got.DoubleValue)
157+
}
158+
} else if tc.value == 0.0 || tc.value == -0.0 {
159+
if got.DoubleValue != 0.0 {
160+
t.Errorf("expected 0, got %v", got.DoubleValue)
161+
}
162+
} else {
163+
if math.Abs(got.DoubleValue - tc.value) > doubleComparisonEpsilon {
164+
t.Errorf("expected %v, got %v", tc.value, got.DoubleValue)
165+
}
166+
}
167+
})
168+
}
169+
}
170+
171+
func TestBinaryDoubleNullableColumn(t *testing.T) {
172+
DB.Migrator().DropTable(&BinaryDoubleTest{})
173+
DB.AutoMigrate(&BinaryDoubleTest{})
174+
175+
// Test NULL value
176+
bd1 := BinaryDoubleTest{
177+
DoubleValue: 1.23,
178+
NullableDouble: nil,
179+
}
180+
if err := DB.Create(&bd1).Error; err != nil {
181+
t.Fatalf("failed to insert with NULL: %v", err)
182+
}
183+
184+
var got1 BinaryDoubleTest
185+
if err := DB.First(&got1, bd1.ID).Error; err != nil {
186+
t.Fatal(err)
187+
}
188+
if got1.NullableDouble != nil {
189+
t.Errorf("expected NULL, got %v", *got1.NullableDouble)
190+
}
191+
192+
// Test with non-NULL value
193+
val := 456.789
194+
bd2 := BinaryDoubleTest{
195+
DoubleValue: 2.34,
196+
NullableDouble: &val,
197+
}
198+
if err := DB.Create(&bd2).Error; err != nil {
199+
t.Fatalf("failed to insert with value: %v", err)
200+
}
201+
202+
var got2 BinaryDoubleTest
203+
if err := DB.First(&got2, bd2.ID).Error; err != nil {
204+
t.Fatal(err)
205+
}
206+
if got2.NullableDouble == nil {
207+
t.Error("expected non-NULL value")
208+
} else if math.Abs(*got2.NullableDouble - val) > doubleComparisonEpsilon {
209+
t.Errorf("expected %v, got %v", val, *got2.NullableDouble)
210+
}
211+
212+
// Update to NULL
213+
if err := DB.Model(&got2).Update("NullableDouble", nil).Error; err != nil {
214+
t.Fatalf("failed to update to NULL: %v", err)
215+
}
216+
217+
var got3 BinaryDoubleTest
218+
if err := DB.First(&got3, bd2.ID).Error; err != nil {
219+
t.Fatal(err)
220+
}
221+
if got3.NullableDouble != nil {
222+
t.Errorf("expected NULL after update, got %v", *got3.NullableDouble)
223+
}
224+
}
225+
226+
func TestBinaryDoubleSQLNullFloat(t *testing.T) {
227+
DB.Migrator().DropTable(&BinaryDoubleTest{})
228+
DB.AutoMigrate(&BinaryDoubleTest{})
229+
230+
// Test with valid value
231+
bd1 := BinaryDoubleTest{
232+
DoubleValue: 1.0,
233+
SQLNullFloat: sql.NullFloat64{Float64: 123.456, Valid: true},
234+
}
235+
if err := DB.Create(&bd1).Error; err != nil {
236+
t.Fatalf("failed to create with sql.NullFloat64: %v", err)
237+
}
238+
239+
var got1 BinaryDoubleTest
240+
if err := DB.First(&got1, bd1.ID).Error; err != nil {
241+
t.Fatal(err)
242+
}
243+
if !got1.SQLNullFloat.Valid {
244+
t.Error("expected Valid to be true")
245+
}
246+
if math.Abs(got1.SQLNullFloat.Float64 - 123.456) > doubleComparisonEpsilon {
247+
t.Errorf("expected 123.456, got %v", got1.SQLNullFloat.Float64)
248+
}
249+
250+
// Test with invalid (NULL) value
251+
bd2 := BinaryDoubleTest{
252+
DoubleValue: 2.0,
253+
SQLNullFloat: sql.NullFloat64{Valid: false},
254+
}
255+
if err := DB.Create(&bd2).Error; err != nil {
256+
t.Fatalf("failed to create with NULL sql.NullFloat64: %v", err)
257+
}
258+
259+
var got2 BinaryDoubleTest
260+
if err := DB.First(&got2, bd2.ID).Error; err != nil {
261+
t.Fatal(err)
262+
}
263+
if got2.SQLNullFloat.Valid {
264+
t.Error("expected Valid to be false for NULL")
265+
}
266+
}
267+
268+
func TestBinaryDoubleArithmeticOperations(t *testing.T) {
269+
DB.Migrator().DropTable(&BinaryDoubleTest{})
270+
DB.AutoMigrate(&BinaryDoubleTest{})
271+
272+
// Insert test data
273+
values := []float64{10.5, 20.3, 30.7, 40.1, 50.9}
274+
for _, v := range values {
275+
bd := BinaryDoubleTest{DoubleValue: v}
276+
if err := DB.Create(&bd).Error; err != nil {
277+
t.Fatalf("failed to insert %v: %v", v, err)
278+
}
279+
}
280+
281+
// Test SUM
282+
var sum float64
283+
if err := DB.Model(&BinaryDoubleTest{}).Select("SUM(DOUBLE_VALUE)").Scan(&sum).Error; err != nil {
284+
t.Fatalf("failed to calculate SUM: %v", err)
285+
}
286+
expectedSum := 10.5 + 20.3 + 30.7 + 40.1 + 50.9
287+
if math.Abs(sum - expectedSum) > doubleAggregateEpsilon {
288+
t.Errorf("expected sum %v, got %v", expectedSum, sum)
289+
}
290+
291+
// Test AVG
292+
var avg float64
293+
if err := DB.Model(&BinaryDoubleTest{}).Select("AVG(DOUBLE_VALUE)").Scan(&avg).Error; err != nil {
294+
t.Fatalf("failed to calculate AVG: %v", err)
295+
}
296+
expectedAvg := expectedSum / 5
297+
if math.Abs(avg - expectedAvg) > doubleAggregateEpsilon {
298+
t.Errorf("expected avg %v, got %v", expectedAvg, avg)
299+
}
300+
301+
// Test MIN/MAX
302+
var min, max float64
303+
if err := DB.Model(&BinaryDoubleTest{}).Select("MIN(DOUBLE_VALUE)").Scan(&min).Error; err != nil {
304+
t.Fatalf("failed to calculate MIN: %v", err)
305+
}
306+
if err := DB.Model(&BinaryDoubleTest{}).Select("MAX(DOUBLE_VALUE)").Scan(&max).Error; err != nil {
307+
t.Fatalf("failed to calculate MAX: %v", err)
308+
}
309+
if math.Abs(min - 10.5) > doubleAggregateEpsilon {
310+
t.Errorf("expected min 10.5, got %v", min)
311+
}
312+
if math.Abs(max - 50.9) > doubleAggregateEpsilon {
313+
t.Errorf("expected max 50.9, got %v", max)
314+
}
315+
}
316+
317+
func TestBinaryDoubleRangeQueries(t *testing.T) {
318+
DB.Migrator().DropTable(&BinaryDoubleTest{})
319+
DB.AutoMigrate(&BinaryDoubleTest{})
320+
321+
// Insert test data with various ranges
322+
testData := []float64{-100.5, -50.0, 0.0, 25.5, 50.0, 75.75, 100.0, 150.25}
323+
for _, v := range testData {
324+
bd := BinaryDoubleTest{DoubleValue: v}
325+
if err := DB.Create(&bd).Error; err != nil {
326+
t.Fatalf("failed to insert %v: %v", v, err)
327+
}
328+
}
329+
330+
// Test BETWEEN query
331+
var results []BinaryDoubleTest
332+
if err := DB.Where("DOUBLE_VALUE BETWEEN ? AND ?", 0.0, 100.0).Find(&results).Error; err != nil {
333+
t.Fatalf("BETWEEN query failed: %v", err)
334+
}
335+
if len(results) != 5 {
336+
t.Errorf("expected 5 results, got %d", len(results))
337+
}
338+
339+
// Test greater than query
340+
var gtResults []BinaryDoubleTest
341+
if err := DB.Where("DOUBLE_VALUE > ?", 50.0).Find(&gtResults).Error; err != nil {
342+
t.Fatalf("> query failed: %v", err)
343+
}
344+
if len(gtResults) != 3 {
345+
t.Errorf("expected 3 results for > 50.0, got %d", len(gtResults))
346+
}
347+
348+
// Test less than or equal query
349+
var lteResults []BinaryDoubleTest
350+
if err := DB.Where("DOUBLE_VALUE <= ?", 0.0).Find(&lteResults).Error; err != nil {
351+
t.Fatalf("<= query failed: %v", err)
352+
}
353+
if len(lteResults) != 3 {
354+
t.Errorf("expected 3 results for <= 0.0, got %d", len(lteResults))
355+
}
356+
357+
// Test equality with floating point
358+
var eqResults []BinaryDoubleTest
359+
if err := DB.Where("DOUBLE_VALUE = ?", 25.5).Find(&eqResults).Error; err != nil {
360+
t.Fatalf("= query failed: %v", err)
361+
}
362+
if len(eqResults) != 1 {
363+
t.Errorf("expected 1 result for = 25.5, got %d", len(eqResults))
364+
}
365+
}

0 commit comments

Comments
 (0)