1#
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 'Union' do
23
24  describe Thrift::Union do
25    it "should return nil value in unset union" do
26      union = SpecNamespace::My_union.new
27      expect(union.get_set_field).to eq(nil)
28      expect(union.get_value).to eq(nil)
29    end
30
31    it "should set a field and be accessible through get_value and the named field accessor" do
32      union = SpecNamespace::My_union.new
33      union.integer32 = 25
34      expect(union.get_set_field).to eq(:integer32)
35      expect(union.get_value).to eq(25)
36      expect(union.integer32).to eq(25)
37    end
38
39    it "should work correctly when instantiated with static field constructors" do
40      union = SpecNamespace::My_union.integer32(5)
41      expect(union.get_set_field).to eq(:integer32)
42      expect(union.integer32).to eq(5)
43    end
44
45    it "should raise for wrong set field" do
46      union = SpecNamespace::My_union.new
47      union.integer32 = 25
48      expect { union.some_characters }.to raise_error(RuntimeError, "some_characters is not union's set field.")
49    end
50
51    it "should raise for wrong set field when hash initialized and type checking is off" do
52      Thrift.type_checking = false
53      union = SpecNamespace::My_union.new({incorrect_field: :incorrect})
54      expect { Thrift::Serializer.new.serialize(union) }.to raise_error(RuntimeError, "set_field is not valid for this union!")
55    end
56
57    it "should not be equal to nil" do
58      union = SpecNamespace::My_union.new
59      expect(union).not_to eq(nil)
60    end
61
62    it "should not be equal with an empty String" do
63      union = SpecNamespace::My_union.new
64      expect(union).not_to eq('')
65    end
66
67    it "should not equate two different unions, i32 vs. string" do
68      union = SpecNamespace::My_union.new(:integer32, 25)
69      other_union = SpecNamespace::My_union.new(:some_characters, "blah!")
70      expect(union).not_to eq(other_union)
71    end
72
73    it "should properly reset setfield and setvalue" do
74      union = SpecNamespace::My_union.new(:integer32, 25)
75      expect(union.get_set_field).to eq(:integer32)
76      union.some_characters = "blah!"
77      expect(union.get_set_field).to eq(:some_characters)
78      expect(union.get_value).to eq("blah!")
79      expect { union.integer32 }.to raise_error(RuntimeError, "integer32 is not union's set field.")
80    end
81
82    it "should not equate two different unions with different values" do
83      union = SpecNamespace::My_union.new(:integer32, 25)
84      other_union = SpecNamespace::My_union.new(:integer32, 400)
85      expect(union).not_to eq(other_union)
86    end
87
88    it "should not equate two different unions with different fields" do
89      union = SpecNamespace::My_union.new(:integer32, 25)
90      other_union = SpecNamespace::My_union.new(:other_i32, 25)
91      expect(union).not_to eq(other_union)
92    end
93
94    it "should inspect properly" do
95      union = SpecNamespace::My_union.new(:integer32, 25)
96      expect(union.inspect).to eq("<SpecNamespace::My_union integer32: 25>")
97    end
98
99    it "should not allow setting with instance_variable_set" do
100      union = SpecNamespace::My_union.new(:integer32, 27)
101      union.instance_variable_set(:@some_characters, "hallo!")
102      expect(union.get_set_field).to eq(:integer32)
103      expect(union.get_value).to eq(27)
104      expect { union.some_characters }.to raise_error(RuntimeError, "some_characters is not union's set field.")
105    end
106
107    it "should serialize to binary correctly" do
108      trans = Thrift::MemoryBufferTransport.new
109      proto = Thrift::BinaryProtocol.new(trans)
110
111      union = SpecNamespace::My_union.new(:integer32, 25)
112      union.write(proto)
113
114      other_union = SpecNamespace::My_union.new(:integer32, 25)
115      other_union.read(proto)
116      expect(other_union).to eq(union)
117    end
118
119    it "should serialize to json correctly" do
120      trans = Thrift::MemoryBufferTransport.new
121      proto = Thrift::JsonProtocol.new(trans)
122
123      union = SpecNamespace::My_union.new(:integer32, 25)
124      union.write(proto)
125
126      other_union = SpecNamespace::My_union.new(:integer32, 25)
127      other_union.read(proto)
128      expect(other_union).to eq(union)
129    end
130
131    it "should raise when validating unset union" do
132      union = SpecNamespace::My_union.new
133      expect { union.validate }.to raise_error(StandardError, "Union fields are not set.")
134
135      other_union = SpecNamespace::My_union.new(:integer32, 1)
136      expect { other_union.validate }.not_to raise_error
137    end
138
139    it "should validate an enum field properly" do
140      union = SpecNamespace::TestUnion.new(:enum_field, 3)
141      expect(union.get_set_field).to eq(:enum_field)
142      expect { union.validate }.to raise_error(Thrift::ProtocolException, "Invalid value of field enum_field!")
143
144      other_union = SpecNamespace::TestUnion.new(:enum_field, 1)
145      expect { other_union.validate }.not_to raise_error
146    end
147
148    it "should properly serialize and match structs with a union" do
149      union = SpecNamespace::My_union.new(:integer32, 26)
150      swu = SpecNamespace::Struct_with_union.new(:fun_union => union)
151
152      trans = Thrift::MemoryBufferTransport.new
153      proto = Thrift::CompactProtocol.new(trans)
154
155      swu.write(proto)
156
157      other_union = SpecNamespace::My_union.new(:some_characters, "hello there")
158      swu2 = SpecNamespace::Struct_with_union.new(:fun_union => other_union)
159
160      expect(swu2).not_to eq(swu)
161
162      swu2.read(proto)
163      expect(swu2).to eq(swu)
164    end
165
166    it "should support old style constructor" do
167      union = SpecNamespace::My_union.new(:integer32 => 26)
168      expect(union.get_set_field).to eq(:integer32)
169      expect(union.get_value).to eq(26)
170    end
171
172    it "should not throw an error when inspected and unset" do
173      expect{SpecNamespace::TestUnion.new().inspect}.not_to raise_error
174    end
175
176    it "should print enum value name when inspected" do
177      expect(SpecNamespace::My_union.new(:some_enum => SpecNamespace::SomeEnum::ONE).inspect).to eq("<SpecNamespace::My_union some_enum: ONE (0)>")
178
179      expect(SpecNamespace::My_union.new(:my_map => {SpecNamespace::SomeEnum::ONE => [SpecNamespace::SomeEnum::TWO]}).inspect).to eq("<SpecNamespace::My_union my_map: {ONE (0): [TWO (1)]}>")
180    end
181
182    it "should offer field? methods" do
183      expect(SpecNamespace::My_union.new.some_enum?).to be_falsey
184      expect(SpecNamespace::My_union.new(:some_enum => SpecNamespace::SomeEnum::ONE).some_enum?).to be_truthy
185      expect(SpecNamespace::My_union.new(:im_true => false).im_true?).to be_truthy
186      expect(SpecNamespace::My_union.new(:im_true => true).im_true?).to be_truthy
187    end
188
189    it "should pretty print binary fields" do
190      expect(SpecNamespace::TestUnion.new(:binary_field => "\001\002\003").inspect).to eq("<SpecNamespace::TestUnion binary_field: 010203>")
191    end
192
193    it "should be comparable" do
194      relationships = [
195        [0,   -1, -1, -1],
196        [1,   0,  -1, -1],
197        [1,   1,  0,  -1],
198        [1,   1,  1,  0]]
199
200      objs = [
201        SpecNamespace::TestUnion.new(:string_field, "blah"),
202        SpecNamespace::TestUnion.new(:string_field, "blahblah"),
203        SpecNamespace::TestUnion.new(:i32_field, 1),
204        SpecNamespace::TestUnion.new()]
205
206      for y in 0..3
207        for x in 0..3
208          # puts "#{objs[y].inspect} <=> #{objs[x].inspect} should == #{relationships[y][x]}"
209          expect(objs[y] <=> objs[x]).to eq(relationships[y][x])
210        end
211      end
212    end
213  end
214end
215