conformance_test.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // Copyright 2019 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package conformance_test
  5. import (
  6. "encoding/binary"
  7. "flag"
  8. "io"
  9. "log"
  10. "os"
  11. "os/exec"
  12. "path/filepath"
  13. "testing"
  14. "google.golang.org/protobuf/encoding/protojson"
  15. "google.golang.org/protobuf/encoding/prototext"
  16. "google.golang.org/protobuf/proto"
  17. pb "google.golang.org/protobuf/internal/testprotos/conformance"
  18. )
  19. func init() {
  20. // When the environment variable RUN_AS_CONFORMANCE_PLUGIN is set,
  21. // we skip running the tests and instead act as a conformance plugin.
  22. // This allows the binary to pass itself to conformance.
  23. if os.Getenv("RUN_AS_CONFORMANCE_PLUGIN") == "1" {
  24. main()
  25. os.Exit(0)
  26. }
  27. }
  28. var (
  29. execute = flag.Bool("execute", false, "execute the conformance test")
  30. protoRoot = flag.String("protoroot", os.Getenv("PROTOBUF_ROOT"), "The root of the protobuf source tree.")
  31. )
  32. func Test(t *testing.T) {
  33. if !*execute {
  34. t.SkipNow()
  35. }
  36. binPath := filepath.Join(*protoRoot, "conformance", "conformance-test-runner")
  37. cmd := exec.Command(binPath,
  38. "--failure_list", "failing_tests.txt",
  39. "--text_format_failure_list", "failing_tests_text_format.txt",
  40. "--enforce_recommended",
  41. os.Args[0])
  42. cmd.Env = append(os.Environ(), "RUN_AS_CONFORMANCE_PLUGIN=1")
  43. out, err := cmd.CombinedOutput()
  44. if err != nil {
  45. t.Fatalf("execution error: %v\n\n%s", err, out)
  46. }
  47. }
  48. func main() {
  49. var sizeBuf [4]byte
  50. inbuf := make([]byte, 0, 4096)
  51. for {
  52. _, err := io.ReadFull(os.Stdin, sizeBuf[:])
  53. if err == io.EOF {
  54. break
  55. }
  56. if err != nil {
  57. log.Fatalf("conformance: read request: %v", err)
  58. }
  59. size := binary.LittleEndian.Uint32(sizeBuf[:])
  60. if int(size) > cap(inbuf) {
  61. inbuf = make([]byte, size)
  62. }
  63. inbuf = inbuf[:size]
  64. if _, err := io.ReadFull(os.Stdin, inbuf); err != nil {
  65. log.Fatalf("conformance: read request: %v", err)
  66. }
  67. req := &pb.ConformanceRequest{}
  68. if err := proto.Unmarshal(inbuf, req); err != nil {
  69. log.Fatalf("conformance: parse request: %v", err)
  70. }
  71. res := handle(req)
  72. out, err := proto.Marshal(res)
  73. if err != nil {
  74. log.Fatalf("conformance: marshal response: %v", err)
  75. }
  76. binary.LittleEndian.PutUint32(sizeBuf[:], uint32(len(out)))
  77. if _, err := os.Stdout.Write(sizeBuf[:]); err != nil {
  78. log.Fatalf("conformance: write response: %v", err)
  79. }
  80. if _, err := os.Stdout.Write(out); err != nil {
  81. log.Fatalf("conformance: write response: %v", err)
  82. }
  83. }
  84. }
  85. func handle(req *pb.ConformanceRequest) (res *pb.ConformanceResponse) {
  86. var msg proto.Message = &pb.TestAllTypesProto2{}
  87. if req.GetMessageType() == "protobuf_test_messages.proto3.TestAllTypesProto3" {
  88. msg = &pb.TestAllTypesProto3{}
  89. }
  90. // Unmarshal the test message.
  91. var err error
  92. switch p := req.Payload.(type) {
  93. case *pb.ConformanceRequest_ProtobufPayload:
  94. err = proto.Unmarshal(p.ProtobufPayload, msg)
  95. case *pb.ConformanceRequest_JsonPayload:
  96. err = protojson.UnmarshalOptions{
  97. DiscardUnknown: req.TestCategory == pb.TestCategory_JSON_IGNORE_UNKNOWN_PARSING_TEST,
  98. }.Unmarshal([]byte(p.JsonPayload), msg)
  99. case *pb.ConformanceRequest_TextPayload:
  100. err = prototext.Unmarshal([]byte(p.TextPayload), msg)
  101. default:
  102. return &pb.ConformanceResponse{
  103. Result: &pb.ConformanceResponse_RuntimeError{
  104. RuntimeError: "unknown request payload type",
  105. },
  106. }
  107. }
  108. if err != nil {
  109. return &pb.ConformanceResponse{
  110. Result: &pb.ConformanceResponse_ParseError{
  111. ParseError: err.Error(),
  112. },
  113. }
  114. }
  115. // Marshal the test message.
  116. var b []byte
  117. switch req.RequestedOutputFormat {
  118. case pb.WireFormat_PROTOBUF:
  119. b, err = proto.Marshal(msg)
  120. res = &pb.ConformanceResponse{
  121. Result: &pb.ConformanceResponse_ProtobufPayload{
  122. ProtobufPayload: b,
  123. },
  124. }
  125. case pb.WireFormat_JSON:
  126. b, err = protojson.Marshal(msg)
  127. res = &pb.ConformanceResponse{
  128. Result: &pb.ConformanceResponse_JsonPayload{
  129. JsonPayload: string(b),
  130. },
  131. }
  132. case pb.WireFormat_TEXT_FORMAT:
  133. b, err = prototext.MarshalOptions{
  134. EmitUnknown: req.PrintUnknownFields,
  135. }.Marshal(msg)
  136. res = &pb.ConformanceResponse{
  137. Result: &pb.ConformanceResponse_TextPayload{
  138. TextPayload: string(b),
  139. },
  140. }
  141. default:
  142. return &pb.ConformanceResponse{
  143. Result: &pb.ConformanceResponse_RuntimeError{
  144. RuntimeError: "unknown output format",
  145. },
  146. }
  147. }
  148. if err != nil {
  149. return &pb.ConformanceResponse{
  150. Result: &pb.ConformanceResponse_SerializeError{
  151. SerializeError: err.Error(),
  152. },
  153. }
  154. }
  155. return res
  156. }