github.com/mithrandie/csvq@v1.18.1/lib/query/sort_value_test.go (about) 1 package query 2 3 import ( 4 "bytes" 5 "math" 6 "testing" 7 "time" 8 9 "github.com/mithrandie/csvq/lib/value" 10 11 "github.com/mithrandie/ternary" 12 ) 13 14 func TestSortValues_Serialize(t *testing.T) { 15 defer func() { 16 TestTx.Flags.StrictEqual = false 17 }() 18 19 values := SortValues{ 20 NewSortValue(value.NewNull(), TestTx.Flags), 21 NewSortValue(value.NewInteger(1), TestTx.Flags), 22 NewSortValue(value.NewFloat(1.234), TestTx.Flags), 23 NewSortValue(value.NewDatetimeFromString("2012-02-03T09:18:15-08:00", TestTx.Flags.DatetimeFormat, TestTx.Flags.GetTimeLocation()), TestTx.Flags), 24 NewSortValue(value.NewDatetimeFromString("2012-02-03T09:18:15.123-08:00", TestTx.Flags.DatetimeFormat, TestTx.Flags.GetTimeLocation()), TestTx.Flags), 25 NewSortValue(value.NewDatetimeFromString("2012-02-03T09:18:15.123456789-08:00", TestTx.Flags.DatetimeFormat, TestTx.Flags.GetTimeLocation()), TestTx.Flags), 26 NewSortValue(value.NewBoolean(false), TestTx.Flags), 27 NewSortValue(value.NewString("str"), TestTx.Flags), 28 } 29 expect := "[N]:[I]1:[F]1.234:[D]1328289495000000000:[D]1328289495123000000:[D]1328289495123456789:[I]0:[S]STR" 30 31 buf := &bytes.Buffer{} 32 values.Serialize(buf) 33 result := buf.String() 34 if result != expect { 35 t.Errorf("result = %q, want %q", result, expect) 36 } 37 38 TestTx.Flags.StrictEqual = true 39 40 values = SortValues{ 41 NewSortValue(value.NewNull(), TestTx.Flags), 42 NewSortValue(value.NewInteger(1), TestTx.Flags), 43 NewSortValue(value.NewFloat(1.234), TestTx.Flags), 44 NewSortValue(value.NewDatetimeFromString("2012-02-03T09:18:15-08:00", TestTx.Flags.DatetimeFormat, TestTx.Flags.GetTimeLocation()), TestTx.Flags), 45 NewSortValue(value.NewDatetimeFromString("2012-02-03T09:18:15.123-08:00", TestTx.Flags.DatetimeFormat, TestTx.Flags.GetTimeLocation()), TestTx.Flags), 46 NewSortValue(value.NewDatetimeFromString("2012-02-03T09:18:15.123456789-08:00", TestTx.Flags.DatetimeFormat, TestTx.Flags.GetTimeLocation()), TestTx.Flags), 47 NewSortValue(value.NewBoolean(false), TestTx.Flags), 48 NewSortValue(value.NewString("str"), TestTx.Flags), 49 } 50 expect = "[N]:[I]1:[F]1.234:[D]1328289495000000000:[D]1328289495123000000:[D]1328289495123456789:[B]F:[S]str" 51 52 buf.Reset() 53 values.Serialize(buf) 54 result = buf.String() 55 if result != expect { 56 t.Errorf("result = %q, want %q", result, expect) 57 } 58 } 59 60 var sortValueLessTests = []struct { 61 Name string 62 SortValue value.Primary 63 CompareValue value.Primary 64 StrictEqual bool 65 Result ternary.Value 66 }{ 67 { 68 Name: "Integer is less than Integer", 69 SortValue: value.NewInteger(3), 70 CompareValue: value.NewInteger(5), 71 StrictEqual: false, 72 Result: ternary.TRUE, 73 }, 74 { 75 Name: "Same Integer", 76 SortValue: value.NewInteger(3), 77 CompareValue: value.NewInteger(3), 78 StrictEqual: false, 79 Result: ternary.UNKNOWN, 80 }, 81 { 82 Name: "Integer is less than Float", 83 SortValue: value.NewInteger(3), 84 CompareValue: value.NewFloat(5.4), 85 StrictEqual: false, 86 Result: ternary.TRUE, 87 }, 88 { 89 Name: "Integer and Datetime cannot be compared", 90 SortValue: value.NewInteger(3), 91 CompareValue: value.NewDatetime(time.Date(2012, 2, 3, 9, 18, 15, 123456789, GetTestLocation())), 92 StrictEqual: false, 93 Result: ternary.UNKNOWN, 94 }, 95 { 96 Name: "Integer is less than String", 97 SortValue: value.NewInteger(3), 98 CompareValue: value.NewString("4a"), 99 StrictEqual: false, 100 Result: ternary.TRUE, 101 }, 102 { 103 Name: "Float is less than Float", 104 SortValue: value.NewFloat(3.4), 105 CompareValue: value.NewFloat(5.1), 106 StrictEqual: false, 107 Result: ternary.TRUE, 108 }, 109 { 110 Name: "Same Float", 111 SortValue: value.NewFloat(3.4), 112 CompareValue: value.NewFloat(3.4), 113 StrictEqual: false, 114 Result: ternary.UNKNOWN, 115 }, 116 { 117 Name: "Float and Datetime cannot be compared", 118 SortValue: value.NewFloat(3.4), 119 CompareValue: value.NewDatetime(time.Date(2012, 2, 3, 9, 18, 15, 123456789, GetTestLocation())), 120 StrictEqual: false, 121 Result: ternary.UNKNOWN, 122 }, 123 { 124 Name: "Float is less than String", 125 SortValue: value.NewFloat(3.4), 126 CompareValue: value.NewString("4a"), 127 StrictEqual: false, 128 Result: ternary.TRUE, 129 }, 130 { 131 Name: "Datetime is less than Datetime", 132 SortValue: value.NewDatetime(time.Date(2012, 2, 3, 9, 18, 15, 123456789, GetTestLocation())), 133 CompareValue: value.NewDatetime(time.Date(2012, 2, 4, 9, 18, 15, 123456789, GetTestLocation())), 134 StrictEqual: false, 135 Result: ternary.TRUE, 136 }, 137 { 138 Name: "Same Datetime", 139 SortValue: value.NewDatetime(time.Date(2012, 2, 3, 9, 18, 15, 123456789, GetTestLocation())), 140 CompareValue: value.NewDatetime(time.Date(2012, 2, 3, 9, 18, 15, 123456789, GetTestLocation())), 141 StrictEqual: false, 142 Result: ternary.UNKNOWN, 143 }, 144 { 145 Name: "String is less than String", 146 SortValue: value.NewString("aaa"), 147 CompareValue: value.NewString("abc"), 148 StrictEqual: false, 149 Result: ternary.TRUE, 150 }, 151 { 152 Name: "String representing integer is less than String representing integer", 153 SortValue: value.NewString("1"), 154 CompareValue: value.NewString("003"), 155 StrictEqual: false, 156 Result: ternary.TRUE, 157 }, 158 { 159 Name: "Character Cases are Ignored", 160 SortValue: value.NewString("aaa"), 161 CompareValue: value.NewString("AAA"), 162 StrictEqual: false, 163 Result: ternary.UNKNOWN, 164 }, 165 { 166 Name: "Boolean and Ternary cannot be compared", 167 SortValue: value.NewBoolean(true), 168 CompareValue: value.NewTernary(ternary.FALSE), 169 StrictEqual: false, 170 Result: ternary.UNKNOWN, 171 }, 172 { 173 Name: "Integer and Ternary cannot be compared", 174 SortValue: value.NewInteger(3), 175 CompareValue: value.NewTernary(ternary.UNKNOWN), 176 StrictEqual: false, 177 Result: ternary.UNKNOWN, 178 }, 179 { 180 Name: "Same Strings when StrictEqual is true", 181 SortValue: value.NewString("abc"), 182 CompareValue: value.NewString("abc"), 183 StrictEqual: true, 184 Result: ternary.UNKNOWN, 185 }, 186 { 187 Name: "When StrictEqual is true, Character Cases are not ignored", 188 SortValue: value.NewString("aaa"), 189 CompareValue: value.NewString("AAA"), 190 StrictEqual: true, 191 Result: ternary.FALSE, 192 }, 193 { 194 Name: "When StrictEqual is true, Strings representing integers are compared as Strings", 195 SortValue: value.NewString("1"), 196 CompareValue: value.NewString("003"), 197 StrictEqual: true, 198 Result: ternary.FALSE, 199 }, 200 { 201 Name: "Float and String are compared even when StrictEqual is true", 202 SortValue: value.NewFloat(3.4), 203 CompareValue: value.NewString("4a"), 204 StrictEqual: true, 205 Result: ternary.TRUE, 206 }, 207 { 208 Name: "-Inf is less than +Inf", 209 SortValue: value.NewFloat(math.Inf(-1)), 210 CompareValue: value.NewFloat(math.Inf(+1)), 211 StrictEqual: false, 212 Result: ternary.TRUE, 213 }, 214 { 215 Name: "-Inf is less than +Inf even when StrictEqual is true", 216 SortValue: value.NewFloat(math.Inf(-1)), 217 CompareValue: value.NewFloat(math.Inf(+1)), 218 StrictEqual: true, 219 Result: ternary.TRUE, 220 }, 221 { 222 Name: "-Inf is less than any float value", 223 SortValue: value.NewFloat(math.Inf(-1)), 224 CompareValue: value.NewFloat(1), 225 StrictEqual: false, 226 Result: ternary.TRUE, 227 }, 228 { 229 Name: "-Inf is less than any float value even when StrictEqual is true", 230 SortValue: value.NewFloat(math.Inf(-1)), 231 CompareValue: value.NewFloat(1), 232 StrictEqual: true, 233 Result: ternary.TRUE, 234 }, 235 { 236 Name: "NaN has the same priority as other NaN", 237 SortValue: value.NewFloat(math.NaN()), 238 CompareValue: value.NewFloat(math.NaN()), 239 StrictEqual: false, 240 Result: ternary.UNKNOWN, 241 }, 242 { 243 Name: "NaN has the same priority as other NaN even when StrictEqual is true", 244 SortValue: value.NewFloat(math.NaN()), 245 CompareValue: value.NewFloat(math.NaN()), 246 StrictEqual: true, 247 Result: ternary.UNKNOWN, 248 }, 249 { 250 Name: "NaN has the highest priority than any float value", 251 SortValue: value.NewFloat(math.NaN()), 252 CompareValue: value.NewFloat(math.Inf(1)), 253 StrictEqual: false, 254 Result: ternary.FALSE, 255 }, 256 { 257 Name: "NaN has the highest priority than any float value even when StrictEqual is true", 258 SortValue: value.NewFloat(math.NaN()), 259 CompareValue: value.NewFloat(math.Inf(1)), 260 StrictEqual: true, 261 Result: ternary.FALSE, 262 }, 263 { 264 Name: "Any float value has a lower priority than NaN", 265 SortValue: value.NewFloat(math.Inf(1)), 266 CompareValue: value.NewFloat(math.NaN()), 267 StrictEqual: false, 268 Result: ternary.TRUE, 269 }, 270 { 271 Name: "Any float value has a lower priority than NaN even when StrictEqual is true", 272 SortValue: value.NewFloat(math.Inf(1)), 273 CompareValue: value.NewFloat(math.NaN()), 274 StrictEqual: true, 275 Result: ternary.TRUE, 276 }, 277 } 278 279 func TestSortValue_Less(t *testing.T) { 280 defer func() { 281 TestTx.Flags.StrictEqual = true 282 }() 283 284 for _, v := range sortValueLessTests { 285 TestTx.Flags.StrictEqual = v.StrictEqual 286 sv1 := NewSortValue(v.SortValue, TestTx.Flags) 287 sv2 := NewSortValue(v.CompareValue, TestTx.Flags) 288 result := sv1.Less(sv2) 289 if result != v.Result { 290 t.Errorf("%s: result = %s, want %s", v.Name, result, v.Result) 291 } 292 } 293 } 294 295 var sortValueEquivalentToTests = []struct { 296 Name string 297 SortValue value.Primary 298 CompareValue value.Primary 299 StrictEqual bool 300 Result bool 301 }{ 302 { 303 Name: "Same Integer", 304 SortValue: value.NewInteger(3), 305 CompareValue: value.NewInteger(3), 306 StrictEqual: false, 307 Result: true, 308 }, 309 { 310 Name: "Integer and Boolean with equivalent values", 311 SortValue: value.NewInteger(1), 312 CompareValue: value.NewBoolean(true), 313 StrictEqual: false, 314 Result: true, 315 }, 316 { 317 Name: "Integer and DateTime with equivalent values", 318 SortValue: value.NewInteger(1328260695), 319 CompareValue: value.NewDatetime(time.Date(2012, 2, 3, 9, 18, 15, 0, GetTestLocation())), 320 StrictEqual: false, 321 Result: false, 322 }, 323 { 324 Name: "Same Float", 325 SortValue: value.NewFloat(3.21), 326 CompareValue: value.NewFloat(3.21), 327 StrictEqual: false, 328 Result: true, 329 }, 330 { 331 Name: "Float and DateTime with equivalent values", 332 SortValue: value.NewFloat(1328260695.0001), 333 CompareValue: value.NewDatetime(time.Date(2012, 2, 3, 9, 18, 15, 100000, GetTestLocation())), 334 StrictEqual: false, 335 Result: false, 336 }, 337 { 338 Name: "Same Datetime", 339 SortValue: value.NewDatetime(time.Date(2012, 2, 3, 9, 18, 15, 123456789, GetTestLocation())), 340 CompareValue: value.NewDatetime(time.Date(2012, 2, 3, 9, 18, 15, 123456789, GetTestLocation())), 341 StrictEqual: false, 342 Result: true, 343 }, 344 { 345 Name: "Same Boolean", 346 SortValue: value.NewBoolean(true), 347 CompareValue: value.NewBoolean(true), 348 StrictEqual: false, 349 Result: true, 350 }, 351 { 352 Name: "Boolean and Integer with equivalent values", 353 SortValue: value.NewBoolean(true), 354 CompareValue: value.NewInteger(1), 355 StrictEqual: false, 356 Result: true, 357 }, 358 { 359 Name: "String and String with equivalent values", 360 SortValue: value.NewString("Str"), 361 CompareValue: value.NewString("str"), 362 StrictEqual: false, 363 Result: true, 364 }, 365 { 366 Name: "Null and Null", 367 SortValue: value.NewNull(), 368 CompareValue: value.NewNull(), 369 StrictEqual: false, 370 Result: true, 371 }, 372 { 373 Name: "String and Null", 374 SortValue: value.NewString("str"), 375 CompareValue: value.NewNull(), 376 StrictEqual: false, 377 Result: false, 378 }, 379 { 380 Name: "When StrictEqual is true, Strings with different case", 381 SortValue: value.NewString("Str"), 382 CompareValue: value.NewString("str"), 383 StrictEqual: true, 384 Result: false, 385 }, 386 { 387 Name: "String and Integer with equivalent values", 388 SortValue: value.NewString("001"), 389 CompareValue: value.NewInteger(1), 390 StrictEqual: false, 391 Result: true, 392 }, 393 { 394 Name: "When StrictEqual is true, Strings and Integer with equivalent values", 395 SortValue: value.NewString("001"), 396 CompareValue: value.NewInteger(1), 397 StrictEqual: true, 398 Result: false, 399 }, 400 { 401 Name: "Inf and NaN are not equivanent", 402 SortValue: value.NewFloat(math.Inf(1)), 403 CompareValue: value.NewFloat(math.NaN()), 404 StrictEqual: false, 405 Result: false, 406 }, 407 { 408 Name: "NaN and NaN are equivanent in sorting", 409 SortValue: value.NewFloat(math.NaN()), 410 CompareValue: value.NewFloat(math.NaN()), 411 StrictEqual: false, 412 Result: true, 413 }, 414 } 415 416 func TestSortValue_EquivalentTo(t *testing.T) { 417 defer func() { 418 TestTx.Flags.StrictEqual = true 419 }() 420 421 for _, v := range sortValueEquivalentToTests { 422 TestTx.Flags.StrictEqual = v.StrictEqual 423 sv1 := NewSortValue(v.SortValue, TestTx.Flags) 424 sv2 := NewSortValue(v.CompareValue, TestTx.Flags) 425 result := sv1.EquivalentTo(sv2) 426 if result != v.Result { 427 t.Errorf("%s: result = %t, want %t", v.Name, result, v.Result) 428 } 429 } 430 } 431 432 var sortValueLessBench1 = NewSortValue(value.NewInteger(12345), TestTx.Flags) 433 var sortValueLessBench2 = NewSortValue(value.NewInteger(67890), TestTx.Flags) 434 435 func BenchmarkSortValue_Less(b *testing.B) { 436 for i := 0; i < b.N; i++ { 437 _ = sortValueLessBench1.Less(sortValueLessBench2) 438 } 439 } 440 441 var sortValuesEquivalentBench1 = SortValues{ 442 NewSortValue(value.NewInteger(12345), TestTx.Flags), 443 NewSortValue(value.NewString("abcdefghijklmnopqrstuvwxymabcdefghijklmnopqrstuvwxyz"), TestTx.Flags), 444 NewSortValue(value.NewDatetime(time.Date(2012, 2, 3, 9, 18, 15, 0, GetTestLocation())), TestTx.Flags), 445 } 446 447 var sortValuesEquivalentBench2 = SortValues{ 448 NewSortValue(value.NewInteger(12345), TestTx.Flags), 449 NewSortValue(value.NewString("abcdefghijklmnopqrstuvwxymabcdefghijklmnopqrstuvwxyz"), TestTx.Flags), 450 NewSortValue(value.NewDatetime(time.Date(2012, 2, 3, 9, 18, 15, 0, GetTestLocation())), TestTx.Flags), 451 } 452 453 func BenchmarkSortValues_EquivalentTo(b *testing.B) { 454 for i := 0; i < b.N; i++ { 455 _ = sortValuesEquivalentBench1.EquivalentTo(sortValuesEquivalentBench2) 456 } 457 }