package binlog import ( "testing" "github.com/starainrt/go-mysql/mysql" "github.com/starainrt/go-mysql/replication" ) func TestNormalizeRowsByUnsigned_AllIntegerKinds(t *testing.T) { event := &replication.RowsEvent{ Table: &replication.TableMapEvent{ ColumnCount: 5, ColumnType: []byte{mysql.MYSQL_TYPE_TINY, mysql.MYSQL_TYPE_SHORT, mysql.MYSQL_TYPE_INT24, mysql.MYSQL_TYPE_LONG, mysql.MYSQL_TYPE_LONGLONG}, SignednessBitmap: []byte{0xF8}, }, Rows: [][]interface{}{{int8(-1), int16(-2), int32(-1), int32(-1), int64(-1)}}, } got := normalizeRowsByUnsigned(event) row := got[0] if v, ok := row[0].(uint8); !ok || v != 255 { t.Fatalf("tiny unsigned mismatch: %T %v", row[0], row[0]) } if v, ok := row[1].(uint16); !ok || v != 65534 { t.Fatalf("short unsigned mismatch: %T %v", row[1], row[1]) } if v, ok := row[2].(uint32); !ok || v != 16777215 { t.Fatalf("int24 unsigned mismatch: %T %v", row[2], row[2]) } if v, ok := row[3].(uint32); !ok || v != 4294967295 { t.Fatalf("long unsigned mismatch: %T %v", row[3], row[3]) } if v, ok := row[4].(uint64); !ok || v != 18446744073709551615 { t.Fatalf("longlong unsigned mismatch: %T %v", row[4], row[4]) } } func TestNormalizeRowsByUnsigned_NoSignednessMetadata(t *testing.T) { event := &replication.RowsEvent{ Table: &replication.TableMapEvent{ ColumnCount: 1, ColumnType: []byte{mysql.MYSQL_TYPE_LONGLONG}, }, Rows: [][]interface{}{{int64(-1)}}, } got := normalizeRowsByUnsigned(event) if v, ok := got[0][0].(int64); !ok || v != -1 { t.Fatalf("value should remain signed when metadata missing: %T %v", got[0][0], got[0][0]) } } func TestParseBinlogEvent_IncludeColumnMetadata(t *testing.T) { event := &replication.RowsEvent{ Table: &replication.TableMapEvent{ ColumnCount: 3, ColumnType: []byte{mysql.MYSQL_TYPE_VAR_STRING, mysql.MYSQL_TYPE_LONG, mysql.MYSQL_TYPE_VAR_STRING}, DefaultCharset: []uint64{45}, // utf8mb4_general_ci }, Rows: [][]interface{}{{"name", int32(1), "desc"}}, } ev := &replication.BinlogEvent{ Header: &replication.EventHeader{EventType: replication.WRITE_ROWS_EVENTv2}, Event: event, } events := ParseBinlogEvent(ev) if len(events) != 1 { t.Fatalf("expected 1 event, got %d", len(events)) } got := events[0] if len(got.ColumnTypes) != 3 { t.Fatalf("unexpected column type length: %d", len(got.ColumnTypes)) } if got.ColumnTypes[0] != int(mysql.MYSQL_TYPE_VAR_STRING) || got.ColumnTypes[1] != int(mysql.MYSQL_TYPE_LONG) { t.Fatalf("unexpected column types: %v", got.ColumnTypes) } if len(got.ColumnCollationIDs) != 3 { t.Fatalf("unexpected column collation length: %d", len(got.ColumnCollationIDs)) } if got.ColumnCollationIDs[0] != 45 { t.Fatalf("unexpected collation for column 0: %d", got.ColumnCollationIDs[0]) } if got.ColumnCollationIDs[2] != 45 { t.Fatalf("unexpected collation for column 2: %d", got.ColumnCollationIDs[2]) } if got.ColumnCollationIDs[1] != 0 { t.Fatalf("non-character column should keep zero collation: %d", got.ColumnCollationIDs[1]) } }