// Copyright (C) MongoDB, Inc. 2017-present. // // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 package primitive import ( "encoding/json" "testing" "time" "github.com/stretchr/testify/require" "go.mongodb.org/mongo-driver/internal/testutil/assert" ) // The same interface as bsoncodec.Zeroer implemented for tests. type zeroer interface { IsZero() bool } func TestTimestampCompare(t *testing.T) { testcases := []struct { name string tp Timestamp tp2 Timestamp expected int }{ {"equal", Timestamp{T: 12345, I: 67890}, Timestamp{T: 12345, I: 67890}, 0}, {"T greater than", Timestamp{T: 12345, I: 67890}, Timestamp{T: 2345, I: 67890}, 1}, {"I greater than", Timestamp{T: 12345, I: 67890}, Timestamp{T: 12345, I: 7890}, 1}, {"T less than", Timestamp{T: 12345, I: 67890}, Timestamp{T: 112345, I: 67890}, -1}, {"I less than", Timestamp{T: 12345, I: 67890}, Timestamp{T: 12345, I: 167890}, -1}, } for _, tc := range testcases { t.Run(tc.name, func(t *testing.T) { result := CompareTimestamp(tc.tp, tc.tp2) require.Equal(t, tc.expected, result) }) } } func TestPrimitiveIsZero(t *testing.T) { testcases := []struct { name string zero zeroer nonzero zeroer }{ {"binary", Binary{}, Binary{Data: []byte{0x01, 0x02, 0x03}, Subtype: 0xFF}}, {"decimal128", Decimal128{}, NewDecimal128(1, 2)}, {"objectID", ObjectID{}, NewObjectID()}, {"regex", Regex{}, Regex{Pattern: "foo", Options: "bar"}}, {"dbPointer", DBPointer{}, DBPointer{DB: "foobar", Pointer: ObjectID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C}}}, {"timestamp", Timestamp{}, Timestamp{T: 12345, I: 67890}}, } for _, tc := range testcases { t.Run(tc.name, func(t *testing.T) { require.True(t, tc.zero.IsZero()) require.False(t, tc.nonzero.IsZero()) }) } } func TestRegexCompare(t *testing.T) { testcases := []struct { name string r1 Regex r2 Regex eq bool }{ {"equal", Regex{Pattern: "foo1", Options: "bar1"}, Regex{Pattern: "foo1", Options: "bar1"}, true}, {"not equal", Regex{Pattern: "foo1", Options: "bar1"}, Regex{Pattern: "foo2", Options: "bar2"}, false}, {"not equal", Regex{Pattern: "foo1", Options: "bar1"}, Regex{Pattern: "foo1", Options: "bar2"}, false}, {"not equal", Regex{Pattern: "foo1", Options: "bar1"}, Regex{Pattern: "foo2", Options: "bar1"}, false}, } for _, tc := range testcases { t.Run(tc.name, func(t *testing.T) { require.True(t, tc.r1.Equal(tc.r2) == tc.eq) }) } } func TestDateTime(t *testing.T) { t.Run("json", func(t *testing.T) { t.Run("round trip", func(t *testing.T) { original := DateTime(1000) jsonBytes, err := json.Marshal(original) assert.Nil(t, err, "Marshal error: %v", err) var unmarshalled DateTime err = json.Unmarshal(jsonBytes, &unmarshalled) assert.Nil(t, err, "Unmarshal error: %v", err) assert.Equal(t, original, unmarshalled, "expected DateTime %v, got %v", original, unmarshalled) }) t.Run("decode null", func(t *testing.T) { jsonBytes := []byte("null") var dt DateTime err := json.Unmarshal(jsonBytes, &dt) assert.Nil(t, err, "Unmarshal error: %v", err) assert.Equal(t, DateTime(0), dt, "expected DateTime value to be 0, got %v", dt) }) }) t.Run("NewDateTimeFromTime", func(t *testing.T) { t.Run("range is not limited", func(t *testing.T) { // If the implementation internally calls time.Time.UnixNano(), the constructor cannot handle times after // the year 2262. timeFormat := "2006-01-02T15:04:05.999Z07:00" timeString := "3001-01-01T00:00:00Z" tt, err := time.Parse(timeFormat, timeString) assert.Nil(t, err, "Parse error: %v", err) dt := NewDateTimeFromTime(tt) assert.True(t, dt > 0, "expected a valid DateTime greater than 0, got %v", dt) }) }) }