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