1 /* Copyright 2017 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 <list>
17
18 #include "tensorflow/core/lib/io/path.h"
19 #include "tensorflow/core/platform/test.h"
20 #include "tensorflow/java/src/gen/cc/java_defs.h"
21 #include "tensorflow/java/src/gen/cc/source_writer.h"
22
23 namespace tensorflow {
24 namespace java {
25 namespace {
26
TEST(AppendTest,SingleLineText)27 TEST(AppendTest, SingleLineText) {
28 SourceBufferWriter writer;
29 writer.Append("You say goodbye and I say hello!");
30
31 const char* expected = "You say goodbye and I say hello!";
32 ASSERT_STREQ(expected, writer.str().data());
33 }
34
TEST(AppendTest,MultiLineText)35 TEST(AppendTest, MultiLineText) {
36 SourceBufferWriter writer;
37 writer.Append("You say goodbye\nand I say hello!");
38
39 const char* expected = "You say goodbye\nand I say hello!";
40 ASSERT_STREQ(expected, writer.str().data());
41 }
42
TEST(AppendTest,MultiLineTextWithIndent)43 TEST(AppendTest, MultiLineTextWithIndent) {
44 SourceBufferWriter writer;
45 writer.Indent(2).Append("You say goodbye\nand I say hello!");
46
47 const char* expected = " You say goodbye\nand I say hello!";
48 ASSERT_STREQ(expected, writer.str().data());
49 }
50
TEST(AppendTest,MultiLineTextWithPrefix)51 TEST(AppendTest, MultiLineTextWithPrefix) {
52 SourceBufferWriter writer;
53 writer.Prefix("--").Append("You say goodbye\nand I say hello!");
54
55 const char* expected = "--You say goodbye\nand I say hello!";
56 ASSERT_STREQ(expected, writer.str().data());
57 }
58
TEST(AppendTest,MultiLineTextWithIndentAndPrefix)59 TEST(AppendTest, MultiLineTextWithIndentAndPrefix) {
60 SourceBufferWriter writer;
61 writer.Indent(2).Prefix("--").Append("You say goodbye\nand I say hello!");
62
63 const char* expected = " --You say goodbye\nand I say hello!";
64 ASSERT_STREQ(expected, writer.str().data());
65 }
66
TEST(WriteTest,SingleLineText)67 TEST(WriteTest, SingleLineText) {
68 SourceBufferWriter writer;
69 writer.Write("You say goodbye and I say hello!");
70
71 const char* expected = "You say goodbye and I say hello!";
72 ASSERT_STREQ(expected, writer.str().data());
73 }
74
TEST(WriteTest,MultiLineText)75 TEST(WriteTest, MultiLineText) {
76 SourceBufferWriter writer;
77 writer.Write("You say goodbye\nand I say hello!");
78
79 const char* expected = "You say goodbye\nand I say hello!";
80 ASSERT_STREQ(expected, writer.str().data());
81 }
82
TEST(WriteTest,MultiLineTextWithIndent)83 TEST(WriteTest, MultiLineTextWithIndent) {
84 SourceBufferWriter writer;
85 writer.Indent(2).Write("You say goodbye\nand I say hello!");
86
87 const char* expected = " You say goodbye\n and I say hello!";
88 ASSERT_STREQ(expected, writer.str().data());
89 }
90
TEST(WriteTest,MultiLineTextWithPrefix)91 TEST(WriteTest, MultiLineTextWithPrefix) {
92 SourceBufferWriter writer;
93 writer.Prefix("--").Write("You say goodbye\nand I say hello!");
94
95 const char* expected = "--You say goodbye\n--and I say hello!";
96 ASSERT_STREQ(expected, writer.str().data());
97 }
98
TEST(WriteTest,MultiLineTextWithIndentAndPrefix)99 TEST(WriteTest, MultiLineTextWithIndentAndPrefix) {
100 SourceBufferWriter writer;
101 writer.Indent(2).Prefix("--").Write("You say goodbye\nand I say hello!");
102
103 const char* expected = " --You say goodbye\n --and I say hello!";
104 ASSERT_STREQ(expected, writer.str().data());
105 }
106
TEST(MarginTest,Basic)107 TEST(MarginTest, Basic) {
108 SourceBufferWriter writer;
109 writer.Append("You say goodbye").EndLine().Append("and I say hello!");
110
111 const char* expected = "You say goodbye\nand I say hello!";
112 ASSERT_STREQ(expected, writer.str().data());
113 }
114
TEST(MarginTest,Indent)115 TEST(MarginTest, Indent) {
116 SourceBufferWriter writer;
117 writer.Append("You say goodbye")
118 .EndLine()
119 .Indent(2)
120 .Append("and I say hello!");
121
122 const char* expected = "You say goodbye\n and I say hello!";
123 ASSERT_STREQ(expected, writer.str().data());
124 }
125
TEST(MarginTest,IndentAndOutdent)126 TEST(MarginTest, IndentAndOutdent) {
127 SourceBufferWriter writer;
128 writer.Append("You say goodbye")
129 .EndLine()
130 .Indent(2)
131 .Append("and I say hello!")
132 .EndLine()
133 .Indent(-2)
134 .Append("Hello, hello!");
135
136 const char* expected = "You say goodbye\n and I say hello!\nHello, hello!";
137 ASSERT_STREQ(expected, writer.str().data());
138 }
139
TEST(MarginTest,Prefix)140 TEST(MarginTest, Prefix) {
141 SourceBufferWriter writer;
142 writer.Append("You say goodbye")
143 .EndLine()
144 .Prefix("--")
145 .Append("and I say hello!");
146
147 const char* expected = "You say goodbye\n--and I say hello!";
148 ASSERT_STREQ(expected, writer.str().data());
149 }
150
TEST(MarginTest,PrefixAndRemovePrefix)151 TEST(MarginTest, PrefixAndRemovePrefix) {
152 SourceBufferWriter writer;
153 writer.Append("You say goodbye")
154 .EndLine()
155 .Prefix("--")
156 .Append("and I say hello!")
157 .EndLine()
158 .Prefix("")
159 .Append("Hello, hello!");
160
161 const char* expected = "You say goodbye\n--and I say hello!\nHello, hello!";
162 ASSERT_STREQ(expected, writer.str().data());
163 }
164
TEST(MarginTest,IndentAndPrefixAndOutdentAndRemovePrefix)165 TEST(MarginTest, IndentAndPrefixAndOutdentAndRemovePrefix) {
166 SourceBufferWriter writer;
167 writer.Append("You say goodbye")
168 .EndLine()
169 .Indent(2)
170 .Prefix("--")
171 .Append("and I say hello!")
172 .EndLine()
173 .Indent(-2)
174 .Prefix("")
175 .Append("Hello, hello!");
176
177 const char* expected = "You say goodbye\n --and I say hello!\nHello, hello!";
178 ASSERT_STREQ(expected, writer.str().data());
179 }
180
TEST(MarginTest,NegativeIndent)181 TEST(MarginTest, NegativeIndent) {
182 SourceBufferWriter writer;
183 writer.Append("You say goodbye")
184 .EndLine()
185 .Indent(-10)
186 .Append("and I say hello!");
187
188 const char* expected = "You say goodbye\nand I say hello!";
189 ASSERT_STREQ(expected, writer.str().data());
190 }
191
TEST(MarginTest,CumulativeIndent)192 TEST(MarginTest, CumulativeIndent) {
193 SourceBufferWriter writer;
194 writer.Append("You say goodbye")
195 .EndLine()
196 .Indent(2)
197 .Append("and I say hello!")
198 .EndLine()
199 .Indent(2)
200 .Append("Hello, hello!");
201
202 const char* expected =
203 "You say goodbye\n and I say hello!\n Hello, hello!";
204 ASSERT_STREQ(expected, writer.str().data());
205 }
206
TEST(MarginTest,EmptyPrefix)207 TEST(MarginTest, EmptyPrefix) {
208 SourceBufferWriter writer;
209 writer.Append("You say goodbye")
210 .EndLine()
211 .Prefix("")
212 .Append("and I say hello!");
213
214 const char* expected = "You say goodbye\nand I say hello!";
215 ASSERT_STREQ(expected, writer.str().data());
216 }
217
TEST(StreamTest,BlocksAndLines)218 TEST(StreamTest, BlocksAndLines) {
219 SourceBufferWriter writer;
220
221 writer.Append("int i = 0;").EndLine()
222 .Append("int j = 10;").EndLine()
223 .Append("if (true)")
224 .BeginBlock()
225 .Append("int aLongWayToTen = 0;").EndLine()
226 .Append("while (++i <= j)")
227 .BeginBlock()
228 .Append("++aLongWayToTen;").EndLine()
229 .EndBlock()
230 .EndBlock();
231
232 const char* expected =
233 "int i = 0;\n"
234 "int j = 10;\n"
235 "if (true) {\n"
236 " int aLongWayToTen = 0;\n"
237 " while (++i <= j) {\n"
238 " ++aLongWayToTen;\n"
239 " }\n"
240 "}\n";
241 ASSERT_STREQ(expected, writer.str().data());
242 }
243
TEST(StreamTest,Types)244 TEST(StreamTest, Types) {
245 SourceBufferWriter writer;
246 Type generic = Type::Generic("T").add_supertype(Type::Class("Number"));
247
248 writer.AppendType(Type::Int())
249 .Append(", ")
250 .AppendType(Type::Class("String"))
251 .Append(", ")
252 .AppendType(generic)
253 .Append(", ")
254 .AppendType(Type::ListOf(generic))
255 .Append(", ")
256 .AppendType(Type::ListOf(Type::IterableOf(generic)))
257 .Append(", ")
258 .AppendType(Type::ListOf(Type::Wildcard()));
259
260 const char* expected =
261 "int, String, T, List<T>, List<Iterable<T>>, List<?>";
262 ASSERT_STREQ(expected, writer.str().data());
263 }
264
TEST(StreamTest,FileSnippet)265 TEST(StreamTest, FileSnippet) {
266 SourceBufferWriter writer;
267 const string fname = tensorflow::io::JoinPath(
268 tensorflow::testing::TensorFlowSrcRoot(),
269 "java/src/gen/resources/test.java.snippet");
270
271 writer.WriteFromFile(fname)
272 .BeginBlock()
273 .WriteFromFile(fname)
274 .EndBlock();
275
276 const char* expected =
277 "// Here is a little snippet\n"
278 "System.out.println(\"Hello!\");\n"
279 "{\n"
280 " // Here is a little snippet\n"
281 " System.out.println(\"Hello!\");\n"
282 "}\n";
283 ASSERT_STREQ(expected, writer.str().data());
284 }
285
TEST(WriteType,SimpleClass)286 TEST(WriteType, SimpleClass) {
287 SourceBufferWriter writer;
288 Type clazz = Type::Class("Test", "org.tensorflow");
289
290 writer.BeginType(clazz, PUBLIC).EndType();
291
292 const char* expected =
293 "package org.tensorflow;\n\n"
294 "public class Test {\n}\n";
295 ASSERT_STREQ(expected, writer.str().data());
296 }
297
TEST(WriteType,SimpleClassWithDependencies)298 TEST(WriteType, SimpleClassWithDependencies) {
299 SourceBufferWriter writer;
300 Type clazz = Type::Class("Test", "org.tensorflow");
301 std::list<Type> deps;
302 deps.push_back(Type::Class("TypeA", "org.test.sub"));
303 deps.push_back(Type::Class("TypeA", "org.test.sub")); // a second time
304 deps.push_back(Type::Class("TypeB", "org.other"));
305 deps.push_back(Type::Class("SamePackageType", "org.tensorflow"));
306 deps.push_back(Type::Class("NoPackageType"));
307
308 writer.BeginType(clazz, PUBLIC, &deps).EndType();
309
310 const char* expected =
311 "package org.tensorflow;\n\n"
312 "import org.other.TypeB;\n"
313 "import org.test.sub.TypeA;\n\n"
314 "public class Test {\n}\n";
315 ASSERT_STREQ(expected, writer.str().data());
316 }
317
TEST(WriteType,AnnotatedAndDocumentedClass)318 TEST(WriteType, AnnotatedAndDocumentedClass) {
319 SourceBufferWriter writer;
320 Type clazz = Type::Class("Test", "org.tensorflow");
321 Javadoc clazz_doc = Javadoc::Create("Javadoc test")
322 .details("This is a\nmultiline description.");
323 clazz.add_annotation(Annotation::Create("Bean"));
324 clazz.add_annotation(Annotation::Create("SuppressWarnings")
325 .attributes("\"rawtypes\""));
326
327 writer.BeginType(clazz, PUBLIC, nullptr, &clazz_doc).EndType();
328
329 const char* expected =
330 "package org.tensorflow;\n\n"
331 "/**\n"
332 " * Javadoc test\n"
333 " * <p>\n"
334 " * This is a\n"
335 " * multiline description.\n"
336 " */\n"
337 "@Bean\n"
338 "@SuppressWarnings(\"rawtypes\")\n"
339 "public class Test {\n}\n";
340 ASSERT_STREQ(expected, writer.str().data());
341 }
342
TEST(WriteType,ParameterizedClass)343 TEST(WriteType, ParameterizedClass) {
344 SourceBufferWriter writer;
345 Type clazz = Type::Class("Test", "org.tensorflow");
346 clazz.add_parameter(Type::Generic("T"));
347 clazz.add_parameter(Type::Generic("U").add_supertype(Type::Class("Number")));
348
349 writer.BeginType(clazz, PUBLIC).EndType();
350
351 const char* expected =
352 "package org.tensorflow;\n\n"
353 "public class Test<T, U extends Number> {\n}\n";
354 ASSERT_STREQ(expected, writer.str().data());
355 }
356
TEST(WriteType,ParameterizedClassAndSupertypes)357 TEST(WriteType, ParameterizedClassAndSupertypes) {
358 SourceBufferWriter writer;
359 Type clazz = Type::Class("Test", "org.tensorflow");
360 Type type_t = Type::Generic("T");
361 clazz.add_parameter(type_t);
362 Type type_u = Type::Generic("U").add_supertype(Type::Class("Number"));
363 clazz.add_parameter(type_u);
364 clazz.add_supertype(Type::Interface("Parameterizable").add_parameter(type_u));
365 clazz.add_supertype(Type::Interface("Runnable"));
366 clazz.add_supertype(Type::Class("SuperTest").add_parameter(type_t));
367
368 writer.BeginType(clazz, PUBLIC).EndType();
369
370 const char* expected =
371 "package org.tensorflow;\n\n"
372 "public class Test<T, U extends Number>"
373 " extends SuperTest<T> implements Parameterizable<U>, Runnable {\n}\n";
374 ASSERT_STREQ(expected, writer.str().data());
375 }
376
TEST(WriteType,ParameterizedClassFields)377 TEST(WriteType, ParameterizedClassFields) {
378 SourceBufferWriter writer;
379 Type clazz = Type::Class("Test", "org.tensorflow");
380 Type type_t = Type::Generic("T").add_supertype(Type::Class("Number"));
381 clazz.add_parameter(type_t);
382 Variable field1 = Variable::Create("field1", Type::Class("String"));
383 Variable field2 = Variable::Create("field2", Type::Class("String"));
384 Variable field3 = Variable::Create("field3", type_t);
385 Javadoc field3_doc = Javadoc::Create("This variable is documented");
386
387 writer.BeginType(clazz, PUBLIC)
388 .WriteField(field1, STATIC | PUBLIC | FINAL)
389 .WriteField(field2, PRIVATE)
390 .WriteField(field3, PRIVATE, &field3_doc)
391 .EndType();
392
393 const char* expected =
394 "package org.tensorflow;\n\n"
395 "public class Test<T extends Number> {\n"
396 " public static final String field1;\n"
397 " private String field2;\n"
398 " /** This variable is documented */\n"
399 " private T field3;\n"
400 "}\n";
401 ASSERT_STREQ(expected, writer.str().data());
402 }
403
TEST(WriteType,SimpleInnerClass)404 TEST(WriteType, SimpleInnerClass) {
405 SourceBufferWriter writer;
406 Type clazz = Type::Class("Test", "org.tensorflow");
407 Type inner_class = Type::Class("InnerTest");
408
409 writer.BeginType(clazz, PUBLIC)
410 .BeginInnerType(inner_class, PUBLIC)
411 .EndType()
412 .EndType();
413
414 const char* expected =
415 "package org.tensorflow;\n\n"
416 "public class Test {\n"
417 " \n"
418 " public class InnerTest {\n"
419 " }\n"
420 "}\n";
421 ASSERT_STREQ(expected, writer.str().data());
422 }
423
TEST(WriteType,StaticParameterizedInnerClass)424 TEST(WriteType, StaticParameterizedInnerClass) {
425 SourceBufferWriter writer;
426 Type clazz = Type::Class("Test", "org.tensorflow");
427 Type type_t = Type::Generic("T").add_supertype(Type::Class("Number"));
428 clazz.add_parameter(type_t);
429 Type inner_class = Type::Class("InnerTest");
430 inner_class.add_parameter(type_t);
431
432 writer.BeginType(clazz, PUBLIC)
433 .BeginInnerType(inner_class, PUBLIC | STATIC)
434 .EndType()
435 .EndType();
436
437 const char* expected =
438 "package org.tensorflow;\n\n"
439 "public class Test<T extends Number> {\n"
440 " \n"
441 " public static class InnerTest<T extends Number> {\n"
442 " }\n"
443 "}\n";
444 ASSERT_STREQ(expected, writer.str().data());
445 }
446
TEST(WriteMethod,SimpleMethod)447 TEST(WriteMethod, SimpleMethod) {
448 SourceBufferWriter writer;
449 Type clazz = Type::Class("Test", "org.tensorflow");
450 Method method = Method::Create("doNothing", Type::Void());
451
452 writer.BeginType(clazz, PUBLIC)
453 .BeginMethod(method, PUBLIC)
454 .EndMethod()
455 .EndType();
456
457 const char* expected =
458 "package org.tensorflow;\n\n"
459 "public class Test {\n"
460 " \n"
461 " public void doNothing() {\n"
462 " }\n"
463 "}\n";
464 ASSERT_STREQ(expected, writer.str().data());
465 }
466
TEST(WriteMethod,AnnotatedAndDocumentedMethod)467 TEST(WriteMethod, AnnotatedAndDocumentedMethod) {
468 SourceBufferWriter writer;
469 Type clazz = Type::Class("Test", "org.tensorflow");
470 Method method = Method::Create("doNothing", Type::Void());
471 Javadoc method_doc =
472 Javadoc::Create("Javadoc test")
473 .details("This method has a\nmultiline description.");
474 method.add_annotation(Annotation::Create("Override"));
475 method.add_annotation(Annotation::Create("SuppressWarnings")
476 .attributes("\"rawtypes\""));
477
478 writer.BeginType(clazz, PUBLIC)
479 .BeginMethod(method, PUBLIC, &method_doc)
480 .EndMethod()
481 .EndType();
482
483 const char* expected =
484 "package org.tensorflow;\n\n"
485 "public class Test {\n"
486 " \n"
487 " /**\n"
488 " * Javadoc test\n"
489 " * <p>\n"
490 " * This method has a\n"
491 " * multiline description.\n"
492 " */\n"
493 " @Override\n"
494 " @SuppressWarnings(\"rawtypes\")\n"
495 " public void doNothing() {\n"
496 " }\n"
497 "}\n";
498 ASSERT_STREQ(expected, writer.str().data());
499 }
500
TEST(WriteMethod,DocumentedMethodWithArguments)501 TEST(WriteMethod, DocumentedMethodWithArguments) {
502 SourceBufferWriter writer;
503 Type clazz = Type::Class("Test", "org.tensorflow");
504 Variable reverse = Variable::Create("reverse", Type::Boolean());
505 Method method = Method::Create("boolToInt", Type::Int());
506 method.add_argument(Variable::Create("b", Type::Boolean()));
507 method.add_argument(reverse);
508 Javadoc method_doc =
509 Javadoc::Create("Converts a boolean to an int")
510 .details("This method will convert\na boolean to an int")
511 .add_param_tag(reverse.name(), "if true, value is reversed")
512 .add_tag("return", "int value for this boolean");
513
514 writer.BeginType(clazz, PUBLIC)
515 .BeginMethod(method, PUBLIC, &method_doc)
516 .Append("if (b && !reverse)")
517 .BeginBlock()
518 .Append("return 1;")
519 .EndLine()
520 .EndBlock()
521 .Append("return 0;")
522 .EndLine()
523 .EndMethod()
524 .EndType();
525
526 const char* expected =
527 "package org.tensorflow;\n\n"
528 "public class Test {\n"
529 " \n"
530 " /**\n"
531 " * Converts a boolean to an int\n"
532 " * <p>\n"
533 " * This method will convert\n"
534 " * a boolean to an int\n"
535 " * \n"
536 " * @param reverse if true, value is reversed\n"
537 " * @return int value for this boolean\n"
538 " */\n"
539 " public int boolToInt(boolean b, boolean reverse) {\n"
540 " if (b && !reverse) {\n"
541 " return 1;\n"
542 " }\n"
543 " return 0;\n"
544 " }\n"
545 "}\n";
546 ASSERT_STREQ(expected, writer.str().data());
547 }
548
TEST(WriteMethod,ParameterizedMethod)549 TEST(WriteMethod, ParameterizedMethod) {
550 SourceBufferWriter writer;
551 Type clazz = Type::Class("Test", "org.tensorflow");
552 Type type_t = Type::Generic("T").add_supertype(Type::Class("Number"));
553 clazz.add_parameter(type_t);
554 Method method = Method::Create("doNothing", type_t);
555
556 writer.BeginType(clazz, PUBLIC)
557 .BeginMethod(method, PUBLIC)
558 .Append("return null;")
559 .EndLine()
560 .EndMethod()
561 .EndType();
562
563 const char* expected =
564 "package org.tensorflow;\n\n"
565 "public class Test<T extends Number> {\n"
566 " \n"
567 " public T doNothing() {\n"
568 " return null;\n"
569 " }\n"
570 "}\n";
571 ASSERT_STREQ(expected, writer.str().data());
572 }
573
TEST(WriteMethod,StaticParameterizedMethod)574 TEST(WriteMethod, StaticParameterizedMethod) {
575 SourceBufferWriter writer;
576 Type clazz = Type::Class("Test", "org.tensorflow");
577 Type type_t = Type::Generic("T").add_supertype(Type::Class("Number"));
578 clazz.add_parameter(type_t);
579 Method method = Method::Create("doNothing", type_t);
580
581 writer.BeginType(clazz, PUBLIC)
582 .BeginMethod(method, PUBLIC | STATIC)
583 .Append("return null;")
584 .EndLine()
585 .EndMethod()
586 .EndType();
587
588 const char* expected =
589 "package org.tensorflow;\n\n"
590 "public class Test<T extends Number> {\n"
591 " \n"
592 " public static <T extends Number> T doNothing() {\n"
593 " return null;\n"
594 " }\n"
595 "}\n";
596 ASSERT_STREQ(expected, writer.str().data());
597 }
598
599 } // namespace
600 } // namespace java
601 } // namespace tensorflow
602