blob: c95d408f0e8bcdd6ab0def6b5fe2bbb12a9d606c [file] [log] [blame]
Dmytro Shteflyuke9ac8e32025-11-19 23:33:23 -05001#
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
20require 'spec_helper'
21
22describe 'UUID Validation' do
23 protocols = [
24 ['BinaryProtocol', Thrift::BinaryProtocol],
25 ]
26
27 if defined?(Thrift::BinaryProtocolAccelerated)
28 protocols << ['BinaryProtocolAccelerated', Thrift::BinaryProtocolAccelerated]
29 end
30
31 protocols << ['CompactProtocol', Thrift::CompactProtocol]
32 protocols << ['JsonProtocol', Thrift::JsonProtocol]
33
34 protocols.each do |protocol_name, protocol_class|
35 describe protocol_name do
36 before(:each) do
37 @trans = Thrift::MemoryBufferTransport.new
38 @prot = protocol_class.new(@trans)
39 end
40
41 context 'valid UUIDs' do
42 it 'should accept lowercase UUIDs' do
43 uuid = '550e8400-e29b-41d4-a716-446655440000'
44 expect { @prot.write_uuid(uuid) }.not_to raise_error
45 result = @prot.read_uuid
46 expect(result).to eq(uuid)
47 end
48
49 it 'should accept uppercase UUIDs' do
50 uuid = '550E8400-E29B-41D4-A716-446655440000'
51 expect { @prot.write_uuid(uuid) }.not_to raise_error
52 result = @prot.read_uuid
53 # Result should be lowercase
54 expect(result).to eq('550e8400-e29b-41d4-a716-446655440000')
55 end
56
57 it 'should accept mixed case UUIDs' do
58 uuid = '550e8400-E29B-41d4-A716-446655440000'
59 expect { @prot.write_uuid(uuid) }.not_to raise_error
60 result = @prot.read_uuid
61 expect(result).to eq('550e8400-e29b-41d4-a716-446655440000')
62 end
63
64 it 'should accept all zeros' do
65 uuid = '00000000-0000-0000-0000-000000000000'
66 expect { @prot.write_uuid(uuid) }.not_to raise_error
67 result = @prot.read_uuid
68 expect(result).to eq(uuid)
69 end
70
71 it 'should accept all fs' do
72 uuid = 'ffffffff-ffff-ffff-ffff-ffffffffffff'
73 expect { @prot.write_uuid(uuid) }.not_to raise_error
74 result = @prot.read_uuid
75 expect(result).to eq(uuid)
76 end
77 end
78
79 context 'invalid UUIDs' do
80 def expect_invalid_uuid(value, message)
81 expect { @prot.write_uuid(value) }.to raise_error(Thrift::ProtocolException) do |error|
82 expect(error.type).to eq(Thrift::ProtocolException::INVALID_DATA)
83 expect(error.message).to eq(message)
84 end
85 end
86
87 it 'should reject nil' do
88 expect_invalid_uuid(nil, 'UUID must be a string')
89 end
90
91 it 'should reject non-string' do
92 expect_invalid_uuid(12345, 'UUID must be a string')
93 end
94
95 it 'should reject wrong length' do
96 expect_invalid_uuid('550e8400-e29b-41d4-a716', 'Invalid UUID format')
97 end
98
99 it 'should reject missing hyphens' do
100 expect_invalid_uuid('550e8400e29b41d4a716446655440000', 'Invalid UUID format')
101 end
102
103 it 'should reject hyphens in wrong positions' do
104 expect_invalid_uuid('550e840-0e29b-41d4-a716-446655440000', 'Invalid UUID format')
105 end
106
107 it 'should reject invalid hex characters (g)' do
108 expect_invalid_uuid('550e8400-e29b-41d4-a716-44665544000g', 'Invalid UUID format')
109 end
110
111 it 'should reject invalid hex characters (z)' do
112 expect_invalid_uuid('z50e8400-e29b-41d4-a716-446655440000', 'Invalid UUID format')
113 end
114
115 it 'should reject invalid hex characters (space)' do
116 expect_invalid_uuid('550e8400-e29b-41d4-a716-44665544000 ', 'Invalid UUID format')
117 end
118
119 it 'should reject empty string' do
120 expect_invalid_uuid('', 'Invalid UUID format')
121 end
122
123 it 'should reject UUID with extra characters' do
124 expect_invalid_uuid('550e8400-e29b-41d4-a716-446655440000x', 'Invalid UUID format')
125 end
126
127 it 'should reject trailing hyphen' do
128 expect_invalid_uuid('550e8400-e29b-41d4-a716-44665544000-', 'Invalid UUID format')
129 end
130
131 it 'should reject hyphen inside hex pair' do
132 expect_invalid_uuid('550e8400-e29b-41d4-a716-4466-5544000', 'Invalid UUID format')
133 end
134 end
135
136 context 'malformed binary data on read' do
137 it 'should raise error on truncated data' do
138 @trans = Thrift::MemoryBufferTransport.new
139 @prot = protocol_class.new(@trans)
140
141 # Write only 10 bytes instead of 16
142 if protocol_class == Thrift::JsonProtocol
143 @trans.write('"00000000-0000-0000-0000"')
144 else
145 @trans.write("\x00" * 10)
146 end
147
148 expect { @prot.read_uuid }.to raise_error(EOFError)
149 end
150
151 it 'should raise error on 15 bytes (one byte short)' do
152 @trans = Thrift::MemoryBufferTransport.new
153 @prot = protocol_class.new(@trans)
154
155 if protocol_class == Thrift::JsonProtocol
156 @trans.write('"00000000-0000-0000-0000-000000000"')
157 else
158 @trans.write("\x00" * 15)
159 end
160
161 expect { @prot.read_uuid }.to raise_error(EOFError)
162 end
163
164 it 'should raise error on empty buffer' do
165 @trans = Thrift::MemoryBufferTransport.new
166 @prot = protocol_class.new(@trans)
167
168 expect { @prot.read_uuid }.to raise_error(EOFError)
169 end
170 end
171
172 context 'multiple UUIDs in sequence' do
173 it 'should handle 10 UUIDs in sequence' do
174 uuids = 10.times.map { |i| sprintf('%08x-0000-0000-0000-000000000000', i) }
175
176 @trans = Thrift::MemoryBufferTransport.new
177 @prot = protocol_class.new(@trans)
178
179 uuids.each { |uuid| @prot.write_uuid(uuid) }
180
181 results = 10.times.map { @prot.read_uuid }
182 expect(results).to eq(uuids)
183 end
184
185 it 'should handle UUIDs interleaved with other types' do
186 @trans = Thrift::MemoryBufferTransport.new
187 @prot = protocol_class.new(@trans)
188
189 @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 0)
190 @prot.write_i32(42)
191 @prot.write_uuid('550e8400-e29b-41d4-a716-446655440000')
192 @prot.write_string('test')
193 @prot.write_uuid('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
194 @prot.write_i64(123456789)
195 @prot.write_message_end
196
197 @prot.read_message_begin
198 expect(@prot.read_i32).to eq(42)
199 expect(@prot.read_uuid).to eq('550e8400-e29b-41d4-a716-446655440000')
200 expect(@prot.read_string).to eq('test')
201 expect(@prot.read_uuid).to eq('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
202 expect(@prot.read_i64).to eq(123456789)
203 @prot.read_message_end
204 end
205
206 it 'should handle UUIDs in struct fields context' do
207 @trans = Thrift::MemoryBufferTransport.new
208 @prot = protocol_class.new(@trans)
209
210 # Simulate struct field headers
211 @prot.write_struct_begin('test')
212 @prot.write_field_begin('uuid1', Thrift::Types::UUID, 1)
213 @prot.write_uuid('550e8400-e29b-41d4-a716-446655440000')
214 @prot.write_field_end
215 @prot.write_field_begin('uuid2', Thrift::Types::UUID, 2)
216 @prot.write_uuid('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
217 @prot.write_field_end
218 @prot.write_field_stop
219 @prot.write_struct_end
220
221 @prot.read_struct_begin
222 name, type, id = @prot.read_field_begin
223 expect(type).to eq(Thrift::Types::UUID)
224 expect(@prot.read_uuid).to eq('550e8400-e29b-41d4-a716-446655440000')
225 @prot.read_field_end
226
227 name, type, id = @prot.read_field_begin
228 expect(type).to eq(Thrift::Types::UUID)
229 expect(@prot.read_uuid).to eq('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
230 @prot.read_field_end
231
232 name, type, id = @prot.read_field_begin
233 expect(type).to eq(Thrift::Types::STOP)
234 end
235 end
236 end
237 end
238end