blob: dcb2968d05e67f69eb9dfe52a60e275a94b72fb4 [file] [log] [blame] [edit]
// Copyright 2026 Google LLC
//
// 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
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package spanner
import (
"bytes"
"fmt"
"math"
"slices"
"sort"
"testing"
)
// buildSignedIntTestValues generates a comprehensive set of signed integer test values.
func buildSignedIntTestValues() []int64 {
values := make(map[int64]bool)
// Range of small values
for i := range 600 {
values[int64(i-300)] = true
}
// Powers of 2 and boundaries
for i := range 63 {
powerOf2 := int64(1) << i
values[powerOf2] = true
values[powerOf2-1] = true
values[powerOf2+1] = true
values[-powerOf2] = true
values[-powerOf2-1] = true
values[-powerOf2+1] = true
}
// Edge cases
values[math.MinInt64] = true
values[math.MaxInt64] = true
result := make([]int64, 0, len(values))
for v := range values {
result = append(result, v)
}
slices.Sort(result)
return result
}
// buildUnsignedIntTestValues generates a comprehensive set of unsigned integer test values.
func buildUnsignedIntTestValues() []uint64 {
values := make(map[uint64]bool)
// Range of small values
for i := range 600 {
values[uint64(i)] = true
}
// Powers of 2 and boundaries (only non-negative values for unsigned)
for i := range 64 {
powerOf2 := uint64(1) << i
values[powerOf2] = true
if powerOf2 > 0 {
values[powerOf2-1] = true
}
if powerOf2 < math.MaxUint64 {
values[powerOf2+1] = true
}
}
result := make([]uint64, 0, len(values))
for v := range values {
result = append(result, v)
}
slices.Sort(result)
return result
}
// ==================== Prefix Successor Tests ====================
func TestSsFormatMakePrefixSuccessor_EmptyInput(t *testing.T) {
result := makePrefixSuccessor(nil)
if result != nil {
t.Errorf("Expected nil for nil input, got %v", result)
}
result = makePrefixSuccessor([]byte{})
if result != nil {
t.Errorf("Expected nil for empty input, got %v", result)
}
}
func TestSsFormatMakePrefixSuccessor_ResultIsGreaterThanOriginal(t *testing.T) {
original := []byte{0x10, 0x20, 0x30}
successor := makePrefixSuccessor(original)
if bytes.Compare(original, successor) >= 0 {
t.Errorf("Successor should be greater than original")
}
}
// ==================== Composite Tag Tests ====================
func TestSsFormatAppendCompositeTag_ShortTag(t *testing.T) {
// Tags 1-15 should fit in 1 byte
for tag := 1; tag <= 15; tag++ {
result, err := appendCompositeTag(nil, tag)
if err != nil {
t.Errorf("Unexpected error for tag %d: %v", tag, err)
continue
}
if len(result) != 1 {
t.Errorf("Tag %d should encode to 1 byte, got %d bytes", tag, len(result))
continue
}
expected := byte(tag << 1)
if result[0] != expected {
t.Errorf("Tag %d should encode as 0x%02X, got 0x%02X", tag, expected, result[0])
}
}
}
func TestSsFormatAppendCompositeTag_MediumTag(t *testing.T) {
// Tags 16-4095 should fit in 2 bytes
testTags := []int{16, 100, 1000, 4095}
for _, tag := range testTags {
result, err := appendCompositeTag(nil, tag)
if err != nil {
t.Errorf("Unexpected error for tag %d: %v", tag, err)
continue
}
if len(result) != 2 {
t.Errorf("Tag %d should encode to 2 bytes, got %d bytes", tag, len(result))
}
}
}
func TestSsFormatAppendCompositeTag_LargeTag(t *testing.T) {
// Tags 4096-65535 should fit in 3 bytes
testTags := []int{4096, 10000, 65535}
for _, tag := range testTags {
result, err := appendCompositeTag(nil, tag)
if err != nil {
t.Errorf("Unexpected error for tag %d: %v", tag, err)
continue
}
if len(result) != 3 {
t.Errorf("Tag %d should encode to 3 bytes, got %d bytes", tag, len(result))
}
}
}
func TestSsFormatAppendCompositeTag_InvalidTag(t *testing.T) {
_, err := appendCompositeTag(nil, 0)
if err == nil {
t.Error("Expected error for tag 0")
}
_, err = appendCompositeTag(nil, -1)
if err == nil {
t.Error("Expected error for tag -1")
}
_, err = appendCompositeTag(nil, 65536)
if err == nil {
t.Error("Expected error for tag 65536")
}
}
func TestSsFormatAppendCompositeTag_PreservesOrdering(t *testing.T) {
// Verify smaller tags encode to lexicographically smaller byte sequences
for tag1 := 1; tag1 <= 100; tag1++ {
for tag2 := tag1 + 1; tag2 <= 101 && tag2 <= tag1+10; tag2++ {
result1, _ := appendCompositeTag(nil, tag1)
result2, _ := appendCompositeTag(nil, tag2)
if bytes.Compare(result1, result2) >= 0 {
t.Errorf("Tag %d should encode smaller than tag %d", tag1, tag2)
}
}
}
}
// ==================== Signed Integer Tests ====================
func TestSsFormatAppendIntIncreasing_PreservesOrdering(t *testing.T) {
testValues := buildSignedIntTestValues()
for i := 0; i < len(testValues)-1; i++ {
v1 := testValues[i]
v2 := testValues[i+1]
result1 := appendIntIncreasing(nil, v1)
result2 := appendIntIncreasing(nil, v2)
if bytes.Compare(result1, result2) >= 0 {
t.Errorf("Encoded %d should be less than encoded %d", v1, v2)
}
}
}
func TestSsFormatAppendIntDecreasing_ReversesOrdering(t *testing.T) {
testValues := buildSignedIntTestValues()
for i := 0; i < len(testValues)-1; i++ {
v1 := testValues[i]
v2 := testValues[i+1]
result1 := appendIntDecreasing(nil, v1)
result2 := appendIntDecreasing(nil, v2)
if bytes.Compare(result1, result2) <= 0 {
t.Errorf("Decreasing encoded %d should be greater than encoded %d", v1, v2)
}
}
}
func TestSsFormatAppendIntIncreasing_EdgeCases(t *testing.T) {
edgeCases := []int64{math.MinInt64, -1, 0, 1, math.MaxInt64}
for _, value := range edgeCases {
result := appendIntIncreasing(nil, value)
if len(result) < 2 {
t.Errorf("Result should have at least 2 bytes for value %d, got %d", value, len(result))
}
if result[0]&0x80 == 0 {
t.Errorf("IS_KEY bit should be set for value %d", value)
}
}
}
// ==================== Unsigned Integer Tests ====================
func TestSsFormatAppendUint64Increasing_PreservesOrdering(t *testing.T) {
testValues := buildUnsignedIntTestValues()
for i := 0; i < len(testValues)-1; i++ {
v1 := testValues[i]
v2 := testValues[i+1]
result1 := appendUint64Increasing(nil, v1)
result2 := appendUint64Increasing(nil, v2)
if bytes.Compare(result1, result2) >= 0 {
t.Errorf("Unsigned encoded %d should be less than %d", v1, v2)
}
}
}
func TestSsFormatAppendUint64Decreasing_ReversesOrdering(t *testing.T) {
values := []uint64{0, 1, 100, 1000, math.MaxUint64}
for i := 0; i < len(values)-1; i++ {
result1 := appendUint64Decreasing(nil, values[i])
result2 := appendUint64Decreasing(nil, values[i+1])
if bytes.Compare(result1, result2) <= 0 {
t.Errorf("Decreasing unsigned encoded %d should be greater than %d", values[i], values[i+1])
}
}
}
// ==================== String Tests ====================
func TestSsFormatAppendStringIncreasing_PreservesOrdering(t *testing.T) {
strings := []string{"", "a", "aa", "ab", "b", "hello", "world", "\xff"}
sort.Strings(strings)
for i := 0; i < len(strings)-1; i++ {
result1 := appendStringIncreasing(nil, strings[i])
result2 := appendStringIncreasing(nil, strings[i+1])
if bytes.Compare(result1, result2) >= 0 {
t.Errorf("Encoded '%s' should be less than '%s'", strings[i], strings[i+1])
}
}
}
func TestSsFormatAppendStringDecreasing_ReversesOrdering(t *testing.T) {
strings := []string{"", "a", "b", "hello"}
for i := 0; i < len(strings)-1; i++ {
result1 := appendStringDecreasing(nil, strings[i])
result2 := appendStringDecreasing(nil, strings[i+1])
if bytes.Compare(result1, result2) <= 0 {
t.Errorf("Decreasing encoded '%s' should be greater than '%s'", strings[i], strings[i+1])
}
}
}
// ==================== Bytes Tests ====================
func TestSsFormatAppendBytesIncreasing_PreservesOrdering(t *testing.T) {
testBytes := [][]byte{
{},
{0x00},
{0x01},
{0x01, 0x02},
{0xFF},
}
for i := 0; i < len(testBytes)-1; i++ {
result1 := appendBytesIncreasing(nil, testBytes[i])
result2 := appendBytesIncreasing(nil, testBytes[i+1])
if bytes.Compare(result1, result2) >= 0 {
t.Errorf("Encoded bytes should maintain lexicographic order")
}
}
}
func TestSsFormatAppendBytesDecreasing_ReversesOrdering(t *testing.T) {
testBytes := [][]byte{
{},
{0x00},
{0x01},
{0x01, 0x02},
{0xFF},
}
for i := 0; i < len(testBytes)-1; i++ {
result1 := appendBytesDecreasing(nil, testBytes[i])
result2 := appendBytesDecreasing(nil, testBytes[i+1])
if bytes.Compare(result1, result2) <= 0 {
t.Errorf("Decreasing encoded bytes should reverse lexicographic order")
}
}
}
func TestSsFormatAppendBytesDecreasing_EscapesSpecialBytes(t *testing.T) {
result := appendBytesDecreasing(nil, []byte{0x00, 0xFF, 0x42})
// Result should be longer due to escaping
if len(result) <= 5 {
t.Errorf("Result should include escape sequences, got length %d", len(result))
}
}
func TestSsFormatAppendBytesDecreasing_EmptyArray(t *testing.T) {
result := appendBytesDecreasing(nil, []byte{})
// Empty bytes should still have header + terminator
if len(result) < 3 {
t.Errorf("Empty bytes encoding should have at least 3 bytes, got %d", len(result))
}
if result[0]&0x80 == 0 {
t.Errorf("IS_KEY bit should be set")
}
}
func TestSsFormatAppendBytesIncreasing_vs_Decreasing_DifferentOutput(t *testing.T) {
input := []byte{0x01, 0x02, 0x03}
resultInc := appendBytesIncreasing(nil, input)
resultDec := appendBytesDecreasing(nil, input)
if bytes.Equal(resultInc, resultDec) {
t.Errorf("Increasing and decreasing encodings should differ")
}
}
// ==================== Double Tests ====================
func TestSsFormatAppendDoubleDecreasing_ReversesOrdering(t *testing.T) {
values := []float64{-math.MaxFloat64, -1.0, 0.0, 1.0, math.MaxFloat64}
for i := 0; i < len(values)-1; i++ {
result1 := appendDoubleDecreasing(nil, values[i])
result2 := appendDoubleDecreasing(nil, values[i+1])
if bytes.Compare(result1, result2) <= 0 {
t.Errorf("Decreasing encoded %v should be greater than %v", values[i], values[i+1])
}
}
}
func TestSsFormatAppendDoubleIncreasing_NegativeZeroEqualsPositiveZero(t *testing.T) {
resultNegZero := appendDoubleIncreasing(nil, math.Copysign(0, -1))
resultPosZero := appendDoubleIncreasing(nil, 0.0)
if !bytes.Equal(resultNegZero, resultPosZero) {
t.Errorf("-0.0 and 0.0 should encode identically")
}
}
func TestSsFormatAppendDoubleIncreasing_NaN(t *testing.T) {
result := appendDoubleIncreasing(nil, math.NaN())
if len(result) < 2 {
t.Errorf("NaN encoding should have at least 2 bytes, got %d", len(result))
}
if result[0]&0x80 == 0 {
t.Errorf("IS_KEY bit should be set for NaN")
}
}
// ==================== Null Marker Tests ====================
func TestSsFormatNullOrderedFirst_SortsBeforeValues(t *testing.T) {
nullResult := appendNullOrderedFirst(nil)
valueResult := appendNotNullMarkerNullOrderedFirst(nil)
valueResult = appendIntIncreasing(valueResult, math.MinInt64)
if bytes.Compare(nullResult, valueResult) >= 0 {
t.Errorf("Null (ordered first) should sort before any value")
}
}
func TestSsFormatNullOrderedLast_SortsAfterValues(t *testing.T) {
nullResult := appendNullOrderedLast(nil)
valueResult := appendNotNullMarkerNullOrderedLast(nil)
valueResult = appendIntIncreasing(valueResult, math.MaxInt64)
if bytes.Compare(nullResult, valueResult) <= 0 {
t.Errorf("Null (ordered last) should sort after any value")
}
}
// ==================== Timestamp Tests ====================
func TestSsFormatEncodeTimestamp_Length(t *testing.T) {
result := encodeTimestamp(0, 0)
if len(result) != 12 {
t.Errorf("Timestamp should encode to 12 bytes, got %d", len(result))
}
}
func TestSsFormatEncodeTimestamp_PreservesOrdering(t *testing.T) {
timestamps := [][2]int64{
{0, 0},
{0, 1},
{0, 999999999},
{1, 0},
{100, 500000000},
{math.MaxInt64 / 2, 0},
}
for i := 0; i < len(timestamps)-1; i++ {
t1 := encodeTimestamp(timestamps[i][0], int32(timestamps[i][1]))
t2 := encodeTimestamp(timestamps[i+1][0], int32(timestamps[i+1][1]))
if bytes.Compare(t1, t2) >= 0 {
t.Errorf("Earlier timestamp should encode smaller")
}
}
}
// ==================== UUID Tests ====================
func TestSsFormatEncodeUUID_Length(t *testing.T) {
result := encodeUUID(0, 0)
if len(result) != 16 {
t.Errorf("UUID should encode to 16 bytes, got %d", len(result))
}
}
func TestSsFormatEncodeUUID_BigEndianEncoding(t *testing.T) {
result := encodeUUID(0x0102030405060708, 0x090A0B0C0D0E0F10)
// Verify big-endian encoding of high bits
expectedHigh := []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}
for i, expected := range expectedHigh {
if result[i] != expected {
t.Errorf("Byte %d should be 0x%02X, got 0x%02X", i, expected, result[i])
}
}
// Verify big-endian encoding of low bits
expectedLow := []byte{0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10}
for i, expected := range expectedLow {
if result[8+i] != expected {
t.Errorf("Byte %d should be 0x%02X, got 0x%02X", 8+i, expected, result[8+i])
}
}
}
func TestSsFormatEncodeUUID_PreservesOrdering(t *testing.T) {
uuids := [][2]int64{
{0, 0},
{0, 1},
{0, math.MaxInt64},
{1, 0},
{math.MaxInt64, math.MaxInt64},
}
for i := 0; i < len(uuids)-1; i++ {
u1 := encodeUUID(uuids[i][0], uuids[i][1])
u2 := encodeUUID(uuids[i+1][0], uuids[i+1][1])
if bytes.Compare(u1, u2) >= 0 {
t.Errorf("UUID ordering should be preserved")
}
}
}
// ==================== Composite Key Tests ====================
func TestSsFormatCompositeKey_TagPlusIntPreservesOrdering(t *testing.T) {
tag := 5
values := []int64{math.MinInt64, -1, 0, 1, math.MaxInt64}
for i := 0; i < len(values)-1; i++ {
result1, _ := appendCompositeTag(nil, tag)
result1 = appendIntIncreasing(result1, values[i])
result2, _ := appendCompositeTag(nil, tag)
result2 = appendIntIncreasing(result2, values[i+1])
if bytes.Compare(result1, result2) >= 0 {
t.Errorf("Composite key with %d should be less than with %d", values[i], values[i+1])
}
}
}
func TestSsFormatCompositeKey_DifferentTagsSortByTag(t *testing.T) {
value := int64(100)
result1, _ := appendCompositeTag(nil, 5)
result1 = appendIntIncreasing(result1, value)
result2, _ := appendCompositeTag(nil, 10)
result2 = appendIntIncreasing(result2, value)
if bytes.Compare(result1, result2) >= 0 {
t.Errorf("Key with smaller tag should sort first")
}
}
func TestSsFormatCompositeKey_MultipleKeyParts(t *testing.T) {
// Simulate encoding a composite key with multiple parts: tag + int + string
result1, _ := appendCompositeTag(nil, 1)
result1 = appendIntIncreasing(result1, 100)
result1 = appendStringIncreasing(result1, "alice")
result2, _ := appendCompositeTag(nil, 1)
result2 = appendIntIncreasing(result2, 100)
result2 = appendStringIncreasing(result2, "bob")
if bytes.Compare(result1, result2) >= 0 {
t.Errorf("Keys with same prefix but different strings should order by string")
}
}
// ==================== Order Preservation Summary Test ====================
func TestSsFormatOrderPreservation_ComprehensiveIntTest(t *testing.T) {
testValues := buildSignedIntTestValues()
// Take a sample of values to avoid O(n^2) test time
step := max(1, len(testValues)/100)
var sample []int64
for i := 0; i < len(testValues); i += step {
sample = append(sample, testValues[i])
}
// Encode all values
var encoded [][]byte
for _, v := range sample {
encoded = append(encoded, appendIntIncreasing(nil, v))
}
// Verify the encoded values are in the same order as the original values
for i := 0; i < len(sample)-1; i++ {
if bytes.Compare(encoded[i], encoded[i+1]) >= 0 {
t.Errorf("Order should be preserved: %d < %d", sample[i], sample[i+1])
}
}
}
// ==================== TargetRange Tests ====================
func TestSsFormatTargetRange_IsPoint(t *testing.T) {
pointRange := newTargetRange([]byte{0x01, 0x02}, nil, false)
if !pointRange.isPoint() {
t.Errorf("Expected isPoint() to return true for empty limit")
}
rangeRange := newTargetRange([]byte{0x01}, []byte{0x02}, false)
if rangeRange.isPoint() {
t.Errorf("Expected isPoint() to return false for non-empty limit")
}
}
func TestSsFormatTargetRange_MergeFrom(t *testing.T) {
r1 := newTargetRange([]byte{0x10}, []byte{0x30}, false)
r2 := newTargetRange([]byte{0x05}, []byte{0x20}, false)
r1.mergeFrom(r2)
// Should take minimum start
if !bytes.Equal(r1.start, []byte{0x05}) {
t.Errorf("Expected start to be 0x05, got %v", r1.start)
}
// Should keep maximum limit
if !bytes.Equal(r1.limit, []byte{0x30}) {
t.Errorf("Expected limit to be 0x30, got %v", r1.limit)
}
}
func TestSsFormatTargetRange_MergeFrom_Approximate(t *testing.T) {
r1 := newTargetRange([]byte{0x10}, []byte{0x30}, false)
r2 := newTargetRange([]byte{0x15}, []byte{0x25}, true)
r1.mergeFrom(r2)
if !r1.approximate {
t.Errorf("Expected approximate to be true after merging with approximate range")
}
}
// ==================== Golden Tests ====================
func TestSsFormatGolden_MakePrefixSuccessor(t *testing.T) {
// Any valid key has the LSB of zero. Thus, setting the LSB of key K to one
// will create a string that's larger than K, but smaller than any valid key
// that does not start with K.
tests := []struct {
name string
input []byte
expected []byte
}{
{"zero byte", []byte{0x00}, []byte{0x01}},
{"even byte", []byte{0x10}, []byte{0x11}},
{"already odd (valid ssformat keys should not have odd LSB)", []byte{0x11}, []byte{0x11}}, // No change since LSB already 1
{"multi-byte key", []byte{0x81, 0x02, 0x58}, []byte{0x81, 0x02, 0x59}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := makePrefixSuccessor(tt.input)
if !bytes.Equal(result, tt.expected) {
t.Errorf("makePrefixSuccessor(%v) = %v, want %v", tt.input, result, tt.expected)
}
})
}
}
func TestSsFormatGolden_CompositeTag(t *testing.T) {
// Verify composite tag encoding produces expected bytes.
tests := []struct {
tag int
expected []byte
}{
// Short tags (1-15): encode as (tag << 1)
{1, []byte{0x02}}, // 1 << 1 = 2
{5, []byte{0x0A}}, // 5 << 1 = 10
{15, []byte{0x1E}}, // 15 << 1 = 30
// Medium tags (16-4095): 2 bytes, header is 001xxxxx (0x20 | tag_bits)
{16, []byte{0x20, 0x20}}, // shiftedTag=32, header=0x20|(32>>8)=0x20, second=32&0xFF=0x20
{100, []byte{0x20, 0xC8}}, // shiftedTag=200, header=0x20, second=0xC8
{4095, []byte{0x3F, 0xFE}}, // shiftedTag=8190, header=0x20|(8190>>8)=0x3F, second=0xFE
// Large tags (4096-65535): 3 bytes, header is 010xxxxx (0x40 | tag_bits)
{4096, []byte{0x40, 0x20, 0x00}}, // shiftedTag=8192=0x2000
{10000, []byte{0x40, 0x4E, 0x20}}, // shiftedTag=20000=0x4E20
}
for _, tt := range tests {
t.Run(fmt.Sprintf("tag_%d", tt.tag), func(t *testing.T) {
result, err := appendCompositeTag(nil, tt.tag)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !bytes.Equal(result, tt.expected) {
t.Errorf("appendCompositeTag(%d) = %v, want %v", tt.tag, result, tt.expected)
}
})
}
}
func TestSsFormatGolden_UnsignedInt(t *testing.T) {
// Verify unsigned integer encoding produces expected bytes.
// Example: 0x1234 = 4660
// LSB byte: (4660 & 0x7F) << 1 = (52) << 1 = 104 = 0x68
// Remaining: 4660 >> 7 = 36 = 0x24
// Type: TYPE_UINT_1 + 2 - 1 = 1, header = 0x80 | 1 = 0x81
tests := []struct {
name string
val uint64
expected []byte
}{
{"zero", 0, []byte{0x80, 0x00}}, // TYPE_UINT_1, payload = 0
{"one", 1, []byte{0x80, 0x02}}, // TYPE_UINT_1, payload = 1<<1 = 2
{"127", 127, []byte{0x80, 0xFE}}, // TYPE_UINT_1, payload = 127<<1 = 254
{"128", 128, []byte{0x81, 0x01, 0x00}}, // TYPE_UINT_2, 128 = (1<<7), so 1 in high, 0 in low<<1
{"0x1234", 0x1234, []byte{0x81, 0x24, 0x68}}, // 0x1234ULL => 81 24 68
{"300", 300, []byte{0x81, 0x02, 0x58}}, // 300 = 0x12C, shifted payload
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := appendUint64Increasing(nil, tt.val)
if !bytes.Equal(result, tt.expected) {
t.Errorf("appendUint64Increasing(%d) = %x, want %x", tt.val, result, tt.expected)
}
})
}
}
func TestSsFormatGolden_SignedInt(t *testing.T) {
// Verify signed integer encoding produces expected bytes.
tests := []struct {
name string
val int64
expected []byte
}{
{"zero", 0, []byte{0x91, 0x00}}, // TYPE_POS_INT_1 = 17, header = 0x80|17 = 0x91
{"positive_1", 1, []byte{0x91, 0x02}}, // 1 << 1 = 2
{"negative_1", -1, []byte{0x90, 0xFE}}, // TYPE_NEG_INT_1 = 16, header = 0x90
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := appendIntIncreasing(nil, tt.val)
if !bytes.Equal(result, tt.expected) {
t.Errorf("appendIntIncreasing(%d) = %x, want %x", tt.val, result, tt.expected)
}
})
}
}
func TestSsFormatGolden_Double(t *testing.T) {
// Verify the double transformation for sortable encoding.
// The transformation maps:
// - Positive doubles (bit 63 = 0) stay as-is
// - Negative doubles (bit 63 = 1) get transformed to maintain ordering
// Test that ordering is preserved across the transformation
orderedDoubles := []float64{
math.Inf(-1),
-math.MaxFloat64,
-1e100,
-1.0,
-1e-100,
-math.SmallestNonzeroFloat64,
0.0,
math.SmallestNonzeroFloat64,
1e-100,
1.0,
1e100,
math.MaxFloat64,
math.Inf(1),
}
var encodings [][]byte
for _, d := range orderedDoubles {
encodings = append(encodings, appendDoubleIncreasing(nil, d))
}
for i := 0; i < len(encodings)-1; i++ {
if bytes.Compare(encodings[i], encodings[i+1]) >= 0 {
t.Errorf("Ordering violated: encoded(%v) >= encoded(%v)", orderedDoubles[i], orderedDoubles[i+1])
}
}
}
func TestSsFormatGolden_String(t *testing.T) {
// Verify string encoding produces expected bytes.
// Header: IS_KEY | TYPE_STRING = 0x80 | 25 = 0x99
// Terminator: 0x00 0x78
// Escape: 0x00 -> 0x00 0xF0, 0xFF -> 0xFF 0x10
tests := []struct {
name string
val string
expected []byte
}{
{"empty", "", []byte{0x99, 0x00, 0x78}}, // header + terminator
{"a", "a", []byte{0x99, 'a', 0x00, 0x78}}, // header + 'a' + terminator
{"hello", "hello", []byte{0x99, 'h', 'e', 'l', 'l', 'o', 0x00, 0x78}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := appendStringIncreasing(nil, tt.val)
if !bytes.Equal(result, tt.expected) {
t.Errorf("appendStringIncreasing(%q) = %x, want %x", tt.val, result, tt.expected)
}
})
}
}
func TestSsFormatGolden_BytesEscaping(t *testing.T) {
// Verify escape sequences produce expected bytes.
// 0x00 => 0x00 0xF0
// 0xFF => 0xFF 0x10
tests := []struct {
name string
val []byte
expected []byte
}{
{"null_byte", []byte{0x00}, []byte{0x99, 0x00, 0xF0, 0x00, 0x78}},
{"ff_byte", []byte{0xFF}, []byte{0x99, 0xFF, 0x10, 0x00, 0x78}},
{"mixed", []byte{0x00, 0x42, 0xFF}, []byte{0x99, 0x00, 0xF0, 0x42, 0xFF, 0x10, 0x00, 0x78}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := appendBytesIncreasing(nil, tt.val)
if !bytes.Equal(result, tt.expected) {
t.Errorf("appendBytesIncreasing(%v) = %x, want %x", tt.val, result, tt.expected)
}
})
}
}
func TestSsFormatGolden_NullMarkers(t *testing.T) {
// Verify NULL marker encoding produces expected bytes.
// TYPE_NULL_ORDERED_FIRST = 27, header = 0x80 | 27 = 0x9B
// TYPE_NULL_ORDERED_LAST = 60, header = 0x80 | 60 = 0xBC
// TYPE_NULLABLE_NOT_NULL_NULL_ORDERED_FIRST = 28, header = 0x80 | 28 = 0x9C
// TYPE_NULLABLE_NOT_NULL_NULL_ORDERED_LAST = 59, header = 0x80 | 59 = 0xBB
if result := appendNullOrderedFirst(nil); !bytes.Equal(result, []byte{0x9B, 0x00}) {
t.Errorf("appendNullOrderedFirst() = %x, want %x", result, []byte{0x9B, 0x00})
}
if result := appendNullOrderedLast(nil); !bytes.Equal(result, []byte{0xBC, 0x00}) {
t.Errorf("appendNullOrderedLast() = %x, want %x", result, []byte{0xBC, 0x00})
}
if result := appendNotNullMarkerNullOrderedFirst(nil); !bytes.Equal(result, []byte{0x9C}) {
t.Errorf("appendNotNullMarkerNullOrderedFirst() = %x, want %x", result, []byte{0x9C})
}
if result := appendNotNullMarkerNullOrderedLast(nil); !bytes.Equal(result, []byte{0xBB}) {
t.Errorf("appendNotNullMarkerNullOrderedLast() = %x, want %x", result, []byte{0xBB})
}
}