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+ type BinaryDoubleTest struct {
48+ ID uint `gorm:"column:ID;primaryKey"`
49+ DoubleValue float64 `gorm:"column:DOUBLE_VALUE;type:BINARY_DOUBLE"`
50+ NullableDouble * float64 `gorm:"column:NULLABLE_DOUBLE;type:BINARY_DOUBLE"`
51+ SQLNullFloat sql.NullFloat64 `gorm:"column:SQL_NULL_FLOAT;type:BINARY_DOUBLE"`
52+ }
53+
54+ func (BinaryDoubleTest ) TableName () string {
55+ return "BINARY_DOUBLE_TESTS"
56+ }
57+
58+ func TestBinaryDoubleBasicCRUD (t * testing.T ) {
59+ DB .Migrator ().DropTable (& BinaryDoubleTest {})
60+ if err := DB .AutoMigrate (& BinaryDoubleTest {}); err != nil {
61+ t .Fatalf ("failed to migrate: %v" , err )
62+ }
63+
64+ // CREATE - Insert basic double value
65+ testValue := 3.141592653589793
66+ bd1 := BinaryDoubleTest {DoubleValue : testValue }
67+ if err := DB .Create (& bd1 ).Error ; err != nil {
68+ t .Fatalf ("insert failed: %v" , err )
69+ }
70+
71+ // READ - Fetch and verify
72+ var got BinaryDoubleTest
73+ if err := DB .First (& got , bd1 .ID ).Error ; err != nil {
74+ t .Fatalf ("fetch failed: %v" , err )
75+ }
76+
77+ if math .Abs (got .DoubleValue - testValue ) > 1e-15 {
78+ t .Errorf ("expected %v, got %v" , testValue , got .DoubleValue )
79+ }
80+
81+ // UPDATE - Modify the value
82+ newValue := 2.718281828459045
83+ if err := DB .Model (& got ).Update ("DoubleValue" , newValue ).Error ; err != nil {
84+ t .Fatalf ("update failed: %v" , err )
85+ }
86+
87+ // Verify update
88+ var updated BinaryDoubleTest
89+ if err := DB .First (& updated , bd1 .ID ).Error ; err != nil {
90+ t .Fatalf ("fetch after update failed: %v" , err )
91+ }
92+ if math .Abs (updated .DoubleValue - newValue ) > 1e-15 {
93+ t .Errorf ("expected %v after update, got %v" , newValue , updated .DoubleValue )
94+ }
95+
96+ // DELETE
97+ if err := DB .Delete (& updated ).Error ; err != nil {
98+ t .Fatalf ("delete failed: %v" , err )
99+ }
100+
101+ // Verify deletion
102+ var deleted BinaryDoubleTest
103+ err := DB .First (& deleted , bd1 .ID ).Error
104+ if err == nil {
105+ t .Error ("expected record to be deleted" )
106+ }
107+ }
108+
109+ func TestBinaryDoubleSpecialValues (t * testing.T ) {
110+ DB .Migrator ().DropTable (& BinaryDoubleTest {})
111+ DB .AutoMigrate (& BinaryDoubleTest {})
112+
113+ testCases := []struct {
114+ name string
115+ value float64
116+ }{
117+ {"Positive Infinity" , math .Inf (1 )},
118+ {"Negative Infinity" , math .Inf (- 1 )},
119+ {"NaN" , math .NaN ()},
120+ {"Max Float64" , math .MaxFloat64 },
121+ {"Min Float64" , - math .MaxFloat64 },
122+ {"Smallest Positive" , math .SmallestNonzeroFloat64 },
123+ {"Zero" , 0.0 },
124+ {"Negative Zero" , - 0.0 },
125+ }
126+
127+ for _ , tc := range testCases {
128+ t .Run (tc .name , func (t * testing.T ) {
129+ bd := BinaryDoubleTest {DoubleValue : tc .value }
130+ if err := DB .Create (& bd ).Error ; err != nil {
131+ t .Fatalf ("failed to insert %s: %v" , tc .name , err )
132+ }
133+
134+ var got BinaryDoubleTest
135+ if err := DB .First (& got , bd .ID ).Error ; err != nil {
136+ t .Fatalf ("failed to fetch %s: %v" , tc .name , err )
137+ }
138+
139+ if math .IsNaN (tc .value ) {
140+ if ! math .IsNaN (got .DoubleValue ) {
141+ t .Errorf ("expected NaN, got %v" , got .DoubleValue )
142+ }
143+ } else if math .IsInf (tc .value , 1 ) {
144+ if ! math .IsInf (got .DoubleValue , 1 ) {
145+ t .Errorf ("expected +Inf, got %v" , got .DoubleValue )
146+ }
147+ } else if math .IsInf (tc .value , - 1 ) {
148+ if ! math .IsInf (got .DoubleValue , - 1 ) {
149+ t .Errorf ("expected -Inf, got %v" , got .DoubleValue )
150+ }
151+ } else if tc .value == 0.0 || tc .value == - 0.0 {
152+ if got .DoubleValue != 0.0 {
153+ t .Errorf ("expected 0, got %v" , got .DoubleValue )
154+ }
155+ } else {
156+ if math .Abs (got .DoubleValue - tc .value ) > 1e-15 {
157+ t .Errorf ("expected %v, got %v" , tc .value , got .DoubleValue )
158+ }
159+ }
160+ })
161+ }
162+ }
163+
164+ func TestBinaryDoubleNullableColumn (t * testing.T ) {
165+ DB .Migrator ().DropTable (& BinaryDoubleTest {})
166+ DB .AutoMigrate (& BinaryDoubleTest {})
167+
168+ // Test NULL value
169+ bd1 := BinaryDoubleTest {
170+ DoubleValue : 1.23 ,
171+ NullableDouble : nil ,
172+ }
173+ if err := DB .Create (& bd1 ).Error ; err != nil {
174+ t .Fatalf ("failed to insert with NULL: %v" , err )
175+ }
176+
177+ var got1 BinaryDoubleTest
178+ if err := DB .First (& got1 , bd1 .ID ).Error ; err != nil {
179+ t .Fatal (err )
180+ }
181+ if got1 .NullableDouble != nil {
182+ t .Errorf ("expected NULL, got %v" , * got1 .NullableDouble )
183+ }
184+
185+ // Test with non-NULL value
186+ val := 456.789
187+ bd2 := BinaryDoubleTest {
188+ DoubleValue : 2.34 ,
189+ NullableDouble : & val ,
190+ }
191+ if err := DB .Create (& bd2 ).Error ; err != nil {
192+ t .Fatalf ("failed to insert with value: %v" , err )
193+ }
194+
195+ var got2 BinaryDoubleTest
196+ if err := DB .First (& got2 , bd2 .ID ).Error ; err != nil {
197+ t .Fatal (err )
198+ }
199+ if got2 .NullableDouble == nil {
200+ t .Error ("expected non-NULL value" )
201+ } else if math .Abs (* got2 .NullableDouble - val ) > 1e-15 {
202+ t .Errorf ("expected %v, got %v" , val , * got2 .NullableDouble )
203+ }
204+
205+ // Update to NULL
206+ if err := DB .Model (& got2 ).Update ("NullableDouble" , nil ).Error ; err != nil {
207+ t .Fatalf ("failed to update to NULL: %v" , err )
208+ }
209+
210+ var got3 BinaryDoubleTest
211+ if err := DB .First (& got3 , bd2 .ID ).Error ; err != nil {
212+ t .Fatal (err )
213+ }
214+ if got3 .NullableDouble != nil {
215+ t .Errorf ("expected NULL after update, got %v" , * got3 .NullableDouble )
216+ }
217+ }
218+
219+ func TestBinaryDoubleSQLNullFloat (t * testing.T ) {
220+ DB .Migrator ().DropTable (& BinaryDoubleTest {})
221+ DB .AutoMigrate (& BinaryDoubleTest {})
222+
223+ // Test with valid value
224+ bd1 := BinaryDoubleTest {
225+ DoubleValue : 1.0 ,
226+ SQLNullFloat : sql.NullFloat64 {Float64 : 123.456 , Valid : true },
227+ }
228+ if err := DB .Create (& bd1 ).Error ; err != nil {
229+ t .Fatalf ("failed to create with sql.NullFloat64: %v" , err )
230+ }
231+
232+ var got1 BinaryDoubleTest
233+ if err := DB .First (& got1 , bd1 .ID ).Error ; err != nil {
234+ t .Fatal (err )
235+ }
236+ if ! got1 .SQLNullFloat .Valid {
237+ t .Error ("expected Valid to be true" )
238+ }
239+ if math .Abs (got1 .SQLNullFloat .Float64 - 123.456 ) > 1e-15 {
240+ t .Errorf ("expected 123.456, got %v" , got1 .SQLNullFloat .Float64 )
241+ }
242+
243+ // Test with invalid (NULL) value
244+ bd2 := BinaryDoubleTest {
245+ DoubleValue : 2.0 ,
246+ SQLNullFloat : sql.NullFloat64 {Valid : false },
247+ }
248+ if err := DB .Create (& bd2 ).Error ; err != nil {
249+ t .Fatalf ("failed to create with NULL sql.NullFloat64: %v" , err )
250+ }
251+
252+ var got2 BinaryDoubleTest
253+ if err := DB .First (& got2 , bd2 .ID ).Error ; err != nil {
254+ t .Fatal (err )
255+ }
256+ if got2 .SQLNullFloat .Valid {
257+ t .Error ("expected Valid to be false for NULL" )
258+ }
259+ }
260+
261+ func TestBinaryDoubleArithmeticOperations (t * testing.T ) {
262+ DB .Migrator ().DropTable (& BinaryDoubleTest {})
263+ DB .AutoMigrate (& BinaryDoubleTest {})
264+
265+ // Insert test data
266+ values := []float64 {10.5 , 20.3 , 30.7 , 40.1 , 50.9 }
267+ for _ , v := range values {
268+ bd := BinaryDoubleTest {DoubleValue : v }
269+ if err := DB .Create (& bd ).Error ; err != nil {
270+ t .Fatalf ("failed to insert %v: %v" , v , err )
271+ }
272+ }
273+
274+ // Test SUM
275+ var sum float64
276+ if err := DB .Model (& BinaryDoubleTest {}).Select ("SUM(DOUBLE_VALUE)" ).Scan (& sum ).Error ; err != nil {
277+ t .Fatalf ("failed to calculate SUM: %v" , err )
278+ }
279+ expectedSum := 10.5 + 20.3 + 30.7 + 40.1 + 50.9
280+ if math .Abs (sum - expectedSum ) > 1e-10 {
281+ t .Errorf ("expected sum %v, got %v" , expectedSum , sum )
282+ }
283+
284+ // Test AVG
285+ var avg float64
286+ if err := DB .Model (& BinaryDoubleTest {}).Select ("AVG(DOUBLE_VALUE)" ).Scan (& avg ).Error ; err != nil {
287+ t .Fatalf ("failed to calculate AVG: %v" , err )
288+ }
289+ expectedAvg := expectedSum / 5
290+ if math .Abs (avg - expectedAvg ) > 1e-10 {
291+ t .Errorf ("expected avg %v, got %v" , expectedAvg , avg )
292+ }
293+
294+ // Test MIN/MAX
295+ var min , max float64
296+ if err := DB .Model (& BinaryDoubleTest {}).Select ("MIN(DOUBLE_VALUE)" ).Scan (& min ).Error ; err != nil {
297+ t .Fatalf ("failed to calculate MIN: %v" , err )
298+ }
299+ if err := DB .Model (& BinaryDoubleTest {}).Select ("MAX(DOUBLE_VALUE)" ).Scan (& max ).Error ; err != nil {
300+ t .Fatalf ("failed to calculate MAX: %v" , err )
301+ }
302+ if math .Abs (min - 10.5 ) > 1e-10 {
303+ t .Errorf ("expected min 10.5, got %v" , min )
304+ }
305+ if math .Abs (max - 50.9 ) > 1e-10 {
306+ t .Errorf ("expected max 50.9, got %v" , max )
307+ }
308+ }
309+
310+ func TestBinaryDoubleRangeQueries (t * testing.T ) {
311+ DB .Migrator ().DropTable (& BinaryDoubleTest {})
312+ DB .AutoMigrate (& BinaryDoubleTest {})
313+
314+ // Insert test data with various ranges
315+ testData := []float64 {- 100.5 , - 50.0 , 0.0 , 25.5 , 50.0 , 75.75 , 100.0 , 150.25 }
316+ for _ , v := range testData {
317+ bd := BinaryDoubleTest {DoubleValue : v }
318+ if err := DB .Create (& bd ).Error ; err != nil {
319+ t .Fatalf ("failed to insert %v: %v" , v , err )
320+ }
321+ }
322+
323+ // Test BETWEEN query
324+ var results []BinaryDoubleTest
325+ if err := DB .Where ("DOUBLE_VALUE BETWEEN ? AND ?" , 0.0 , 100.0 ).Find (& results ).Error ; err != nil {
326+ t .Fatalf ("BETWEEN query failed: %v" , err )
327+ }
328+ if len (results ) != 5 {
329+ t .Errorf ("expected 5 results, got %d" , len (results ))
330+ }
331+
332+ // Test greater than query
333+ var gtResults []BinaryDoubleTest
334+ if err := DB .Where ("DOUBLE_VALUE > ?" , 50.0 ).Find (& gtResults ).Error ; err != nil {
335+ t .Fatalf ("> query failed: %v" , err )
336+ }
337+ if len (gtResults ) != 3 {
338+ t .Errorf ("expected 3 results for > 50.0, got %d" , len (gtResults ))
339+ }
340+
341+ // Test less than or equal query
342+ var lteResults []BinaryDoubleTest
343+ if err := DB .Where ("DOUBLE_VALUE <= ?" , 0.0 ).Find (& lteResults ).Error ; err != nil {
344+ t .Fatalf ("<= query failed: %v" , err )
345+ }
346+ if len (lteResults ) != 3 {
347+ t .Errorf ("expected 3 results for <= 0.0, got %d" , len (lteResults ))
348+ }
349+
350+ // Test equality with floating point
351+ var eqResults []BinaryDoubleTest
352+ if err := DB .Where ("DOUBLE_VALUE = ?" , 25.5 ).Find (& eqResults ).Error ; err != nil {
353+ t .Fatalf ("= query failed: %v" , err )
354+ }
355+ if len (eqResults ) != 1 {
356+ t .Errorf ("expected 1 result for = 25.5, got %d" , len (eqResults ))
357+ }
358+ }
0 commit comments