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  }