1 /* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15
16 #include "tensorflow/core/framework/fake_input.h"
17 #include "tensorflow/core/framework/node_def_builder.h"
18 #include "tensorflow/core/framework/tensor.h"
19 #include "tensorflow/core/framework/tensor_testutil.h"
20 #include "tensorflow/core/framework/types.h"
21 #include "tensorflow/core/framework/variant.h"
22 #include "tensorflow/core/framework/variant_encode_decode.h"
23 #include "tensorflow/core/framework/variant_tensor_data.h"
24 #include "tensorflow/core/kernels/ops_testutil.h"
25 #include "tensorflow/core/kernels/ops_util.h"
26 #include "tensorflow/core/lib/core/status_test_util.h"
27
28 namespace tensorflow {
29 namespace {
30
31 class AsStringGraphTest : public OpsTestBase {
32 protected:
Init(DataType input_type,const string & fill="",int width=-1,int precision=-1,bool scientific=false,bool shortest=false)33 Status Init(DataType input_type, const string& fill = "", int width = -1,
34 int precision = -1, bool scientific = false,
35 bool shortest = false) {
36 TF_CHECK_OK(NodeDefBuilder("op", "AsString")
37 .Input(FakeInput(input_type))
38 .Attr("fill", fill)
39 .Attr("precision", precision)
40 .Attr("scientific", scientific)
41 .Attr("shortest", shortest)
42 .Attr("width", width)
43 .Finalize(node_def()));
44 return InitOp();
45 }
46 };
47
TEST_F(AsStringGraphTest,Int8)48 TEST_F(AsStringGraphTest, Int8) {
49 TF_ASSERT_OK(Init(DT_INT8));
50
51 AddInputFromArray<int8>(TensorShape({3}), {-42, 0, 42});
52 TF_ASSERT_OK(RunOpKernel());
53 Tensor expected(allocator(), DT_STRING, TensorShape({3}));
54 test::FillValues<tstring>(&expected, {"-42", "0", "42"});
55 test::ExpectTensorEqual<tstring>(expected, *GetOutput(0));
56 }
57
TEST_F(AsStringGraphTest,Int64)58 TEST_F(AsStringGraphTest, Int64) {
59 TF_ASSERT_OK(Init(DT_INT64));
60
61 AddInputFromArray<int64_t>(TensorShape({3}), {-42, 0, 42});
62 TF_ASSERT_OK(RunOpKernel());
63 Tensor expected(allocator(), DT_STRING, TensorShape({3}));
64 test::FillValues<tstring>(&expected, {"-42", "0", "42"});
65 test::ExpectTensorEqual<tstring>(expected, *GetOutput(0));
66 }
67
TEST_F(AsStringGraphTest,FloatDefault)68 TEST_F(AsStringGraphTest, FloatDefault) {
69 TF_ASSERT_OK(Init(DT_FLOAT));
70
71 AddInputFromArray<float>(TensorShape({4}), {-42, 0, 3.14159, 42});
72 TF_ASSERT_OK(RunOpKernel());
73 Tensor expected(allocator(), DT_STRING, TensorShape({4}));
74 test::FillValues<tstring>(
75 &expected, {"-42.000000", "0.000000", "3.141590", "42.000000"});
76 test::ExpectTensorEqual<tstring>(expected, *GetOutput(0));
77 }
78
TEST_F(AsStringGraphTest,FloatScientific)79 TEST_F(AsStringGraphTest, FloatScientific) {
80 TF_ASSERT_OK(Init(DT_FLOAT, /*fill=*/"", /*width=*/-1, /*precision=*/-1,
81 /*scientific=*/true));
82
83 AddInputFromArray<float>(TensorShape({4}), {-42, 0, 3.14159, 42});
84 TF_ASSERT_OK(RunOpKernel());
85 Tensor expected(allocator(), DT_STRING, TensorShape({4}));
86 test::FillValues<tstring>(&expected, {"-4.200000e+01", "0.000000e+00",
87 "3.141590e+00", "4.200000e+01"});
88 test::ExpectTensorEqual<tstring>(expected, *GetOutput(0));
89 }
90
TEST_F(AsStringGraphTest,FloatShortest)91 TEST_F(AsStringGraphTest, FloatShortest) {
92 TF_ASSERT_OK(Init(DT_FLOAT, /*fill=*/"", /*width=*/-1, /*precision=*/-1,
93 /*scientific=*/false, /*shortest=*/true));
94
95 AddInputFromArray<float>(TensorShape({4}), {-42, 0, 3.14159, 42});
96 TF_ASSERT_OK(RunOpKernel());
97 Tensor expected(allocator(), DT_STRING, TensorShape({4}));
98 test::FillValues<tstring>(&expected, {"-42", "0", "3.14159", "42"});
99 test::ExpectTensorEqual<tstring>(expected, *GetOutput(0));
100 }
101
TEST_F(AsStringGraphTest,FloatPrecisionOnly)102 TEST_F(AsStringGraphTest, FloatPrecisionOnly) {
103 TF_ASSERT_OK(Init(DT_FLOAT, /*fill=*/"", /*width=*/-1, /*precision=*/2));
104
105 AddInputFromArray<float>(TensorShape({4}), {-42, 0, 3.14159, 42});
106 TF_ASSERT_OK(RunOpKernel());
107 Tensor expected(allocator(), DT_STRING, TensorShape({4}));
108 test::FillValues<tstring>(&expected, {"-42.00", "0.00", "3.14", "42.00"});
109 test::ExpectTensorEqual<tstring>(expected, *GetOutput(0));
110 }
111
TEST_F(AsStringGraphTest,FloatWidthOnly)112 TEST_F(AsStringGraphTest, FloatWidthOnly) {
113 TF_ASSERT_OK(Init(DT_FLOAT, /*fill=*/"", /*width=*/5));
114
115 AddInputFromArray<float>(TensorShape({4}), {-42, 0, 3.14159, 42});
116 TF_ASSERT_OK(RunOpKernel());
117 Tensor expected(allocator(), DT_STRING, TensorShape({4}));
118 test::FillValues<tstring>(
119 &expected, {"-42.000000", "0.000000", "3.141590", "42.000000"});
120 test::ExpectTensorEqual<tstring>(expected, *GetOutput(0));
121 }
122
TEST_F(AsStringGraphTest,Float_5_2_Format)123 TEST_F(AsStringGraphTest, Float_5_2_Format) {
124 TF_ASSERT_OK(Init(DT_FLOAT, /*fill=*/"", /*width=*/5, /*precision=*/2));
125
126 AddInputFromArray<float>(TensorShape({4}), {-42, 0, 3.14159, 42});
127 TF_ASSERT_OK(RunOpKernel());
128 Tensor expected(allocator(), DT_STRING, TensorShape({4}));
129 test::FillValues<tstring>(&expected, {"-42.00", " 0.00", " 3.14", "42.00"});
130 test::ExpectTensorEqual<tstring>(expected, *GetOutput(0));
131 }
132
TEST_F(AsStringGraphTest,Complex)133 TEST_F(AsStringGraphTest, Complex) {
134 TF_ASSERT_OK(Init(DT_COMPLEX64, /*fill=*/"", /*width=*/5, /*precision=*/2));
135
136 AddInputFromArray<complex64>(TensorShape({3}), {{-4, 2}, {0}, {3.14159, -1}});
137 TF_ASSERT_OK(RunOpKernel());
138 Tensor expected(allocator(), DT_STRING, TensorShape({3}));
139 test::FillValues<tstring>(
140 &expected, {"(-4.00, 2.00)", "( 0.00, 0.00)", "( 3.14,-1.00)"});
141 test::ExpectTensorEqual<tstring>(expected, *GetOutput(0));
142 }
143
TEST_F(AsStringGraphTest,Bool)144 TEST_F(AsStringGraphTest, Bool) {
145 TF_ASSERT_OK(Init(DT_BOOL));
146
147 AddInputFromArray<bool>(TensorShape({2}), {true, false});
148 TF_ASSERT_OK(RunOpKernel());
149 Tensor expected(allocator(), DT_STRING, TensorShape({2}));
150 test::FillValues<tstring>(&expected, {"true", "false"});
151 test::ExpectTensorEqual<tstring>(expected, *GetOutput(0));
152 }
153
TEST_F(AsStringGraphTest,Variant)154 TEST_F(AsStringGraphTest, Variant) {
155 TF_ASSERT_OK(Init(DT_VARIANT));
156
157 AddInput(DT_VARIANT, TensorShape({4}));
158 auto inputs = mutable_input(0)->flat<Variant>();
159 inputs(0) = 2;
160 inputs(1) = 3;
161 inputs(2) = true;
162 inputs(3) = Tensor("hi");
163 TF_ASSERT_OK(RunOpKernel());
164 Tensor expected(allocator(), DT_STRING, TensorShape({4}));
165 test::FillValues<tstring>(
166 &expected, {"Variant<type: int value: 2>", "Variant<type: int value: 3>",
167 "Variant<type: bool value: 1>",
168 ("Variant<type: tensorflow::Tensor value: Tensor<type: string"
169 " shape: [] values: hi>>")});
170 test::ExpectTensorEqual<tstring>(expected, *GetOutput(0));
171 }
172
TEST_F(AsStringGraphTest,String)173 TEST_F(AsStringGraphTest, String) {
174 Status s = Init(DT_STRING);
175 ASSERT_EQ(error::INVALID_ARGUMENT, s.code());
176 ASSERT_TRUE(absl::StrContains(
177 s.error_message(),
178 "Value for attr 'T' of string is not in the list of allowed values"));
179 }
180
TEST_F(AsStringGraphTest,OnlyOneOfScientificAndShortest)181 TEST_F(AsStringGraphTest, OnlyOneOfScientificAndShortest) {
182 Status s = Init(DT_FLOAT, /*fill=*/"", /*width=*/-1, /*precision=*/-1,
183 /*scientific=*/true, /*shortest=*/true);
184 ASSERT_EQ(error::INVALID_ARGUMENT, s.code());
185 ASSERT_TRUE(
186 absl::StrContains(s.error_message(),
187 "Cannot select both scientific and shortest notation"));
188 }
189
TEST_F(AsStringGraphTest,NoShortestForNonFloat)190 TEST_F(AsStringGraphTest, NoShortestForNonFloat) {
191 Status s = Init(DT_INT32, /*fill=*/"", /*width=*/-1, /*precision=*/-1,
192 /*scientific=*/false, /*shortest=*/true);
193 ASSERT_EQ(error::INVALID_ARGUMENT, s.code());
194 ASSERT_TRUE(absl::StrContains(
195 s.error_message(),
196 "scientific and shortest format not supported for datatype"));
197 }
198
TEST_F(AsStringGraphTest,NoScientificForNonFloat)199 TEST_F(AsStringGraphTest, NoScientificForNonFloat) {
200 Status s = Init(DT_INT32, /*fill=*/"", /*width=*/-1, /*precision=*/-1,
201 /*scientific=*/true);
202 ASSERT_EQ(error::INVALID_ARGUMENT, s.code());
203 ASSERT_TRUE(absl::StrContains(
204 s.error_message(),
205 "scientific and shortest format not supported for datatype"));
206 }
207
TEST_F(AsStringGraphTest,NoPrecisionForNonFloat)208 TEST_F(AsStringGraphTest, NoPrecisionForNonFloat) {
209 Status s = Init(DT_INT32, /*fill=*/"", /*width=*/-1, /*precision=*/5);
210 ASSERT_EQ(error::INVALID_ARGUMENT, s.code());
211 ASSERT_TRUE(absl::StrContains(s.error_message(),
212 "precision not supported for datatype"));
213 }
214
TEST_F(AsStringGraphTest,LongFill)215 TEST_F(AsStringGraphTest, LongFill) {
216 Status s = Init(DT_INT32, /*fill=*/"asdf");
217 ASSERT_EQ(error::INVALID_ARGUMENT, s.code());
218 ASSERT_TRUE(absl::StrContains(s.error_message(),
219 "Fill string must be one or fewer characters"));
220 }
221
TEST_F(AsStringGraphTest,FillWithZero)222 TEST_F(AsStringGraphTest, FillWithZero) {
223 TF_ASSERT_OK(Init(DT_INT64, /*fill=*/"0", /*width=*/4));
224
225 AddInputFromArray<int64_t>(TensorShape({3}), {-42, 0, 42});
226 TF_ASSERT_OK(RunOpKernel());
227 Tensor expected(allocator(), DT_STRING, TensorShape({3}));
228 test::FillValues<tstring>(&expected, {"-042", "0000", "0042"});
229 test::ExpectTensorEqual<tstring>(expected, *GetOutput(0));
230 }
231
TEST_F(AsStringGraphTest,FillWithSpace)232 TEST_F(AsStringGraphTest, FillWithSpace) {
233 TF_ASSERT_OK(Init(DT_INT64, /*fill=*/" ", /*width=*/4));
234
235 AddInputFromArray<int64_t>(TensorShape({3}), {-42, 0, 42});
236 TF_ASSERT_OK(RunOpKernel());
237 Tensor expected(allocator(), DT_STRING, TensorShape({3}));
238 test::FillValues<tstring>(&expected, {" -42", " 0", " 42"});
239 test::ExpectTensorEqual<tstring>(expected, *GetOutput(0));
240 }
241
TEST_F(AsStringGraphTest,FillWithChar1)242 TEST_F(AsStringGraphTest, FillWithChar1) {
243 TF_ASSERT_OK(Init(DT_INT64, /*fill=*/"-", /*width=*/4));
244
245 AddInputFromArray<int64_t>(TensorShape({3}), {-42, 0, 42});
246 TF_ASSERT_OK(RunOpKernel());
247 Tensor expected(allocator(), DT_STRING, TensorShape({3}));
248 test::FillValues<tstring>(&expected, {"-42 ", "0 ", "42 "});
249 test::ExpectTensorEqual<tstring>(expected, *GetOutput(0));
250 }
251
TEST_F(AsStringGraphTest,FillWithChar3)252 TEST_F(AsStringGraphTest, FillWithChar3) {
253 Status s = Init(DT_INT32, /*fill=*/"s");
254 ASSERT_EQ(error::INVALID_ARGUMENT, s.code());
255 ASSERT_TRUE(
256 absl::StrContains(s.error_message(), "Fill argument not supported"));
257 }
258
TEST_F(AsStringGraphTest,FillWithChar4)259 TEST_F(AsStringGraphTest, FillWithChar4) {
260 Status s = Init(DT_INT32, /*fill=*/"n");
261 ASSERT_EQ(error::INVALID_ARGUMENT, s.code());
262 ASSERT_TRUE(
263 absl::StrContains(s.error_message(), "Fill argument not supported"));
264 }
265
266 } // end namespace
267 } // end namespace tensorflow
268