package natsutil import ( "testing" "google.golang.org/protobuf/proto" pb "git.daviestechlabs.io/daviestechlabs/handler-base/gen/messagespb" ) // ──────────────────────────────────────────────────────────────────────────── // Decode tests // ──────────────────────────────────────────────────────────────────────────── func TestDecode_ChatRequest_Roundtrip(t *testing.T) { orig := &pb.ChatRequest{ RequestId: "req-001", UserId: "user-42", Premium: true, TopK: 10, } data, err := proto.Marshal(orig) if err != nil { t.Fatal(err) } var decoded pb.ChatRequest if err := Decode(data, &decoded); err != nil { t.Fatal(err) } if decoded.GetRequestId() != "req-001" { t.Errorf("RequestId = %v", decoded.GetRequestId()) } if decoded.GetUserId() != "user-42" { t.Errorf("UserId = %v", decoded.GetUserId()) } if decoded.GetPremium() != true { t.Errorf("Premium = %v", decoded.GetPremium()) } if decoded.GetTopK() != 10 { t.Errorf("TopK = %v", decoded.GetTopK()) } } func TestDecode_EmptyMessage(t *testing.T) { data, err := proto.Marshal(&pb.ChatRequest{}) if err != nil { t.Fatal(err) } var decoded pb.ChatRequest if err := Decode(data, &decoded); err != nil { t.Fatal(err) } if decoded.GetRequestId() != "" { t.Errorf("expected empty RequestId, got %q", decoded.GetRequestId()) } } func TestDecode_InvalidData(t *testing.T) { err := Decode([]byte{0xFF, 0xFE}, &pb.ChatRequest{}) if err == nil { t.Error("expected error for invalid protobuf data") } } // ──────────────────────────────────────────────────────────────────────────── // Typed struct roundtrip tests // ──────────────────────────────────────────────────────────────────────────── func TestDecode_VoiceResponse_Roundtrip(t *testing.T) { orig := &pb.VoiceResponse{ RequestId: "vr-001", Response: "The capital of France is Paris.", Transcription: "What is the capital of France?", } data, err := proto.Marshal(orig) if err != nil { t.Fatal(err) } var decoded pb.VoiceResponse if err := Decode(data, &decoded); err != nil { t.Fatal(err) } if decoded.GetRequestId() != orig.GetRequestId() { t.Errorf("RequestId = %q, want %q", decoded.GetRequestId(), orig.GetRequestId()) } if decoded.GetResponse() != orig.GetResponse() { t.Errorf("Response = %q, want %q", decoded.GetResponse(), orig.GetResponse()) } if decoded.GetTranscription() != orig.GetTranscription() { t.Errorf("Transcription = %q, want %q", decoded.GetTranscription(), orig.GetTranscription()) } } func TestDecode_ErrorResponse_Roundtrip(t *testing.T) { orig := &pb.ErrorResponse{ Error: true, Message: "something broke", Type: "InternalError", } data, err := proto.Marshal(orig) if err != nil { t.Fatal(err) } var decoded pb.ErrorResponse if err := Decode(data, &decoded); err != nil { t.Fatal(err) } if !decoded.GetError() { t.Error("expected Error=true") } if decoded.GetMessage() != "something broke" { t.Errorf("Message = %q", decoded.GetMessage()) } if decoded.GetType() != "InternalError" { t.Errorf("Type = %q", decoded.GetType()) } } // ──────────────────────────────────────────────────────────────────────────── // Binary data tests (audio []byte in protobuf) // ──────────────────────────────────────────────────────────────────────────── func TestBinaryDataRoundtrip(t *testing.T) { audio := make([]byte, 32768) for i := range audio { audio[i] = byte(i % 256) } orig := &pb.TTSAudioChunk{ SessionId: "sess-audio-001", Audio: audio, SampleRate: 24000, } data, err := proto.Marshal(orig) if err != nil { t.Fatal(err) } var decoded pb.TTSAudioChunk if err := Decode(data, &decoded); err != nil { t.Fatal(err) } if len(decoded.GetAudio()) != len(orig.GetAudio()) { t.Fatalf("audio len = %d, want %d", len(decoded.GetAudio()), len(orig.GetAudio())) } for i := range decoded.GetAudio() { if decoded.GetAudio()[i] != orig.GetAudio()[i] { t.Fatalf("audio[%d] = %d, want %d", i, decoded.GetAudio()[i], orig.GetAudio()[i]) } } } // TestProtoWireSize shows protobuf wire size for binary payloads. func TestProtoWireSize(t *testing.T) { audio := make([]byte, 16384) msg := &pb.TTSAudioChunk{ SessionId: "sess-1", Audio: audio, } data, _ := proto.Marshal(msg) t.Logf("TTSAudioChunk with 16KB audio: %d bytes on wire", len(data)) } // ──────────────────────────────────────────────────────────────────────────── // Benchmarks // ──────────────────────────────────────────────────────────────────────────── func BenchmarkEncode_ChatRequest(b *testing.B) { data := &pb.ChatRequest{ RequestId: "req-bench", UserId: "user-bench", Message: "What is the weather today?", Premium: true, TopK: 10, } for b.Loop() { _, _ = proto.Marshal(data) } } func BenchmarkDecode_ChatRequest(b *testing.B) { raw, _ := proto.Marshal(&pb.ChatRequest{ RequestId: "req-bench", UserId: "user-bench", Message: "What is the weather today?", Premium: true, TopK: 10, }) for b.Loop() { var m pb.ChatRequest _ = Decode(raw, &m) } } func BenchmarkDecode_Audio32KB(b *testing.B) { raw, _ := proto.Marshal(&pb.TTSAudioChunk{ SessionId: "s1", Audio: make([]byte, 32768), SampleRate: 24000, }) for b.Loop() { var m pb.TTSAudioChunk _ = Decode(raw, &m) } }