blob: 634cce7cfcf00deb02b6ae15c7dde8ad1af5ecc4 [file] [log] [blame]
Copilot13cdb442026-03-17 15:08:29 -07001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20/**
21 * Test file to verify that generated code compiles and works correctly when
22 * both private_optional and template_streamop options are enabled together.
23 */
24
25#include <iostream>
26#include <sstream>
27#include <string>
28#include <cassert>
29#include <type_traits>
30#include <cstring>
31#include <cstdio>
32#include <cstdint>
33
34// Include generated thrift types with private_optional,template_streamop options
35#include "ThriftTest_types.h"
36#include <thrift/TToString.h>
37
38using namespace thrift::test;
39
40// SFINAE helpers to verify field accessibility at compile time.
41// Each requires a separate template because C++ template parameters cannot be
42// string literals, so each field name gets its own specialisation.
43template<typename T, typename = void>
44struct has_public_aa : std::false_type {};
45
46template<typename T>
47struct has_public_aa<T, decltype(void(std::declval<T>().aa))> : std::true_type {};
48
49// SFINAE test to check if required field 'ab' is directly accessible
50template<typename T, typename = void>
51struct has_public_ab : std::false_type {};
52
53template<typename T>
54struct has_public_ab<T, decltype(void(std::declval<T>().ab))> : std::true_type {};
55
56// Custom minimal stream - verifies that template_streamop works with non-std streams
57class MinimalStream {
58private:
59 std::string buf_;
60public:
61 MinimalStream& operator<<(const std::string& s) { buf_ += s; return *this; }
62 MinimalStream& operator<<(const char* s) { buf_ += s; return *this; }
63 MinimalStream& operator<<(char c) { buf_ += c; return *this; }
64 MinimalStream& operator<<(int32_t i) { buf_ += std::to_string(i); return *this; }
65 MinimalStream& operator<<(int64_t i) { buf_ += std::to_string(i); return *this; }
66 MinimalStream& operator<<(uint32_t i) { buf_ += std::to_string(i); return *this; }
67 MinimalStream& operator<<(uint64_t i) { buf_ += std::to_string(i); return *this; }
68 MinimalStream& operator<<(double d) {
69 char tmp[64];
70 std::snprintf(tmp, sizeof(tmp), "%g", d);
71 buf_ += tmp;
72 return *this;
73 }
74 MinimalStream& operator<<(bool b) { buf_ += (b ? "true" : "false"); return *this; }
75 const std::string& str() const { return buf_; }
76};
77
78int main() {
79 std::cout << "Testing private_optional + template_streamop combined..." << std::endl;
80
81 // Compile-time: optional field 'aa' in StructB must be private
82 static_assert(!has_public_aa<StructB>::value,
83 "Optional field 'aa' in StructB should be private with private_optional");
84 std::cout << " ✓ Compile-time: optional field 'aa' is private in StructB" << std::endl;
85
86 // Compile-time: required field 'ab' in StructB must remain public
87 static_assert(has_public_ab<StructB>::value,
88 "Required field 'ab' in StructB should remain public");
89 std::cout << " ✓ Compile-time: required field 'ab' is public in StructB" << std::endl;
90
91 // Test 1: private_optional getters/setters work
92 {
93 Xtruct x;
94 x.__set_string_thing("hello");
95 x.__set_i32_thing(42);
96 assert(x.__get_string_thing() == "hello");
97 assert(x.__get_i32_thing() == 42);
98 std::cout << " ✓ private_optional getters/setters work on Xtruct" << std::endl;
99 }
100
101 // Test 2: template_streamop with std::ostringstream
102 {
103 Xtruct x;
104 x.__set_string_thing("stream test");
105 x.__set_i32_thing(99);
106
107 std::ostringstream oss;
108 oss << x;
109 std::string result = oss.str();
110
111 assert(!result.empty());
112 assert(result.find("stream test") != std::string::npos);
113 assert(result.find("99") != std::string::npos);
114 std::cout << " ✓ template_streamop works with std::ostringstream" << std::endl;
115 }
116
117 // Test 3: template_streamop with custom MinimalStream
118 {
119 Xtruct x;
120 x.__set_string_thing("minimal stream");
121 x.__set_i32_thing(7);
122
123 MinimalStream ms;
124 ms << x;
125 std::string result = ms.str();
126
127 assert(!result.empty());
128 assert(result.find("minimal stream") != std::string::npos);
129 assert(result.find("7") != std::string::npos);
130 std::cout << " ✓ template_streamop works with custom MinimalStream" << std::endl;
131 }
132
133 // Test 4: Stream a struct whose optional fields were set via setters (combines both options)
134 {
135 StructB sb;
136 StructA sa;
137 sa.__set_s("optional value");
138
139 // private_optional: must use setter, not direct assignment
140 sb.__set_aa(sa);
141 // required field: direct access is still fine
142 sb.ab = sa;
143
144 // template_streamop: stream the struct to both stream types
145 std::ostringstream oss;
146 oss << sb;
147 std::string oss_result = oss.str();
148
149 MinimalStream ms;
150 ms << sb;
151 std::string ms_result = ms.str();
152
153 assert(!oss_result.empty());
154 assert(!ms_result.empty());
155 assert(oss_result.find("optional value") != std::string::npos);
156 assert(ms_result.find("optional value") != std::string::npos);
157 std::cout << " ✓ Combined: StructB with private optional fields streams correctly" << std::endl;
158 }
159
160 // Test 5: to_string works with combined options
161 {
162 Xtruct x;
163 x.__set_string_thing("to_string test");
164 x.__set_i32_thing(123);
165
166 std::string s = apache::thrift::to_string(x);
167 assert(!s.empty());
168 assert(s.find("to_string test") != std::string::npos);
169 std::cout << " ✓ to_string works with combined options" << std::endl;
170 }
171
172 std::cout << "\n✅ All private_optional + template_streamop combined tests passed!" << std::endl;
173 return 0;
174}