1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.arch.persistence.room.processor
18
19import COMMON
20import android.arch.persistence.room.parser.SQLTypeAffinity
21import android.arch.persistence.room.processor.ProcessorErrors.PRIMARY_KEY_NULL
22import android.arch.persistence.room.processor.ProcessorErrors.RELATION_IN_ENTITY
23import android.arch.persistence.room.vo.CallType
24import android.arch.persistence.room.vo.Field
25import android.arch.persistence.room.vo.FieldGetter
26import android.arch.persistence.room.vo.FieldSetter
27import android.arch.persistence.room.vo.Index
28import android.arch.persistence.room.vo.Pojo
29import com.google.testing.compile.JavaFileObjects
30import org.hamcrest.CoreMatchers.`is`
31import org.hamcrest.MatcherAssert.assertThat
32import org.junit.Test
33import org.junit.runner.RunWith
34import org.junit.runners.JUnit4
35import javax.lang.model.type.TypeKind.INT
36
37@RunWith(JUnit4::class)
38class EntityProcessorTest : BaseEntityParserTest() {
39    @Test
40    fun simple() {
41        singleEntity("""
42                @PrimaryKey
43                private int id;
44                public int getId() { return id; }
45                public void setId(int id) { this.id = id; }
46            """) { entity, invocation ->
47            assertThat(entity.type.toString(), `is`("foo.bar.MyEntity"))
48            assertThat(entity.fields.size, `is`(1))
49            val field = entity.fields.first()
50            val intType = invocation.processingEnv.typeUtils.getPrimitiveType(INT)
51            assertThat(field, `is`(Field(
52                    element = field.element,
53                    name = "id",
54                    type = intType,
55                    columnName = "id",
56                    affinity = SQLTypeAffinity.INTEGER)))
57            assertThat(field.setter, `is`(FieldSetter("setId", intType, CallType.METHOD)))
58            assertThat(field.getter, `is`(FieldGetter("getId", intType, CallType.METHOD)))
59            assertThat(entity.primaryKey.fields, `is`(listOf(field)))
60        }.compilesWithoutError()
61    }
62
63    @Test
64    fun noGetter() {
65        singleEntity("""
66                @PrimaryKey
67                private int id;
68                public void setId(int id) {this.id = id;}
69                """) { _, _ -> }
70                .failsToCompile()
71                .withErrorContaining(ProcessorErrors.CANNOT_FIND_GETTER_FOR_FIELD)
72    }
73
74    @Test
75    fun getterWithBadType() {
76        singleEntity("""
77                @PrimaryKey
78                private int id;
79                public float getId() {return 0f;}
80                public void setId(int id) {this.id = id;}
81                """) { _, _ -> }
82                .failsToCompile()
83                .withErrorContaining(ProcessorErrors.CANNOT_FIND_GETTER_FOR_FIELD)
84    }
85
86    @Test
87    fun setterWithBadType() {
88        singleEntity("""
89                @PrimaryKey
90                private int id;
91                public int getId() {return id;}
92                public void setId(float id) {}
93                """) { _, _ -> }
94                .failsToCompile()
95                .withErrorContaining(ProcessorErrors.CANNOT_FIND_SETTER_FOR_FIELD)
96    }
97
98    @Test
99    fun setterWithAssignableType() {
100        singleEntity("""
101                @PrimaryKey
102                private int id;
103                public int getId() {return id;}
104                public void setId(Integer id) {}
105                """) { _, _ -> }
106                .compilesWithoutError()
107    }
108
109    @Test
110    fun getterWithAssignableType() {
111        singleEntity("""
112                @PrimaryKey
113                private int id;
114                public Integer getId() {return id;}
115                public void setId(int id) {}
116                """) { _, _ -> }
117                .compilesWithoutError()
118    }
119
120    @Test
121    fun noSetter() {
122        singleEntity("""
123                @PrimaryKey
124                private int id;
125                public int getId(){ return id; }
126                """) { _, _ -> }
127                .failsToCompile()
128                .withErrorContaining(ProcessorErrors.CANNOT_FIND_SETTER_FOR_FIELD)
129    }
130
131    @Test
132    fun tooManyGetters() {
133        singleEntity("""
134                @PrimaryKey
135                private int id;
136                public void setId(int id) {}
137                public int getId(){ return id; }
138                public int id(){ return id; }
139                """) { _, _ -> }
140                .failsToCompile()
141                .withErrorContaining("getId, id")
142    }
143
144    @Test
145    fun tooManyGettersWithIgnore() {
146        singleEntity("""
147                @PrimaryKey
148                private int id;
149                public void setId(int id) {}
150                public int getId(){ return id; }
151                @Ignore public int id(){ return id; }
152                """) { entity, _ ->
153            assertThat(entity.fields.first().getter.name, `is`("getId"))
154        }.compilesWithoutError()
155    }
156
157    @Test
158    fun tooManyGettersWithDifferentVisibility() {
159        singleEntity("""
160                @PrimaryKey
161                private int id;
162                public void setId(int id) {}
163                public int getId(){ return id; }
164                protected int id(){ return id; }
165                """) { entity, _ ->
166            assertThat(entity.fields.first().getter.name, `is`("getId"))
167        }.compilesWithoutError()
168    }
169
170    @Test
171    fun tooManyGettersWithDifferentTypes() {
172        singleEntity("""
173                @PrimaryKey
174                public int id;
175                public void setId(int id) {}
176                public int getId(){ return id; }
177                """) { entity, _ ->
178            assertThat(entity.fields.first().getter.name, `is`("id"))
179            assertThat(entity.fields.first().getter.callType, `is`(CallType.FIELD))
180        }.compilesWithoutError()
181    }
182
183    @Test
184    fun tooManySetters() {
185        singleEntity("""
186                @PrimaryKey
187                private int id;
188                public void setId(int id) {}
189                public void id(int id) {}
190                public int getId(){ return id; }
191                """) { _, _ -> }
192                .failsToCompile()
193                .withErrorContaining("setId, id")
194    }
195
196    @Test
197    fun tooManySettersWithIgnore() {
198        singleEntity("""
199                @PrimaryKey
200                private int id;
201                public void setId(int id) {}
202                @Ignore public void id(int id) {}
203                public int getId(){ return id; }
204                """) { entity, _ ->
205            assertThat(entity.fields.first().setter.name, `is`("setId"))
206        }.compilesWithoutError()
207    }
208
209    @Test
210    fun tooManySettersWithDifferentVisibility() {
211        singleEntity("""
212                @PrimaryKey
213                private int id;
214                public void setId(int id) {}
215                protected void id(int id) {}
216                public int getId(){ return id; }
217                """) { entity, _ ->
218            assertThat(entity.fields.first().setter.name, `is`("setId"))
219        }.compilesWithoutError()
220    }
221
222    @Test
223    fun tooManySettersWithDifferentTypes() {
224        singleEntity("""
225                @PrimaryKey
226                public int id;
227                public void setId(int id) {}
228                public int getId(){ return id; }
229                """) { entity, _ ->
230            assertThat(entity.fields.first().setter.name, `is`("id"))
231            assertThat(entity.fields.first().setter.callType, `is`(CallType.FIELD))
232        }.compilesWithoutError()
233    }
234
235    @Test
236    fun preferPublicOverProtected() {
237        singleEntity("""
238                @PrimaryKey
239                int id;
240                public void setId(int id) {}
241                public int getId(){ return id; }
242                """) { entity, _ ->
243            assertThat(entity.fields.first().setter.name, `is`("setId"))
244            assertThat(entity.fields.first().getter.name, `is`("getId"))
245        }.compilesWithoutError()
246    }
247
248    @Test
249    fun customName() {
250        singleEntity("""
251                @PrimaryKey
252                int x;
253                """, hashMapOf(Pair("tableName", "\"foo_table\""))) { entity, _ ->
254            assertThat(entity.tableName, `is`("foo_table"))
255        }.compilesWithoutError()
256    }
257
258    @Test
259    fun emptyCustomName() {
260        singleEntity("""
261                @PrimaryKey
262                int x;
263                """, hashMapOf(Pair("tableName", "\" \""))) { _, _ ->
264        }.failsToCompile().withErrorContaining(ProcessorErrors.ENTITY_TABLE_NAME_CANNOT_BE_EMPTY)
265    }
266
267    @Test
268    fun missingPrimaryKey() {
269        singleEntity("""
270                """) { _, _ ->
271        }.failsToCompile()
272                .withErrorContaining(ProcessorErrors.MISSING_PRIMARY_KEY)
273    }
274
275    @Test
276    fun missingColumnAdapter() {
277        singleEntity("""
278                @PrimaryKey
279                public java.util.Date myDate;
280                """) { _, _ ->
281
282        }.failsToCompile().withErrorContaining(ProcessorErrors.CANNOT_FIND_COLUMN_TYPE_ADAPTER)
283    }
284
285    @Test
286    fun dropSubPrimaryKey() {
287        singleEntity(
288                """
289                @PrimaryKey
290                int id;
291                @Embedded
292                Point myPoint;
293                static class Point {
294                    @PrimaryKey
295                    int x;
296                    int y;
297                }
298                """
299        ) { entity, _ ->
300            assertThat(entity.primaryKey.fields.map { it.name }, `is`(listOf("id")))
301        }.compilesWithoutError()
302                .withWarningCount(1)
303                .withWarningContaining(ProcessorErrors.embeddedPrimaryKeyIsDropped(
304                        "foo.bar.MyEntity", "x"))
305    }
306
307    @Test
308    fun ignoreDropSubPrimaryKey() {
309        singleEntity(
310                """
311                @PrimaryKey
312                int id;
313                @Embedded
314                @SuppressWarnings(RoomWarnings.PRIMARY_KEY_FROM_EMBEDDED_IS_DROPPED)
315                Point myPoint;
316                static class Point {
317                    @PrimaryKey
318                    int x;
319                    int y;
320                }
321                """
322        ) { entity, _ ->
323            assertThat(entity.primaryKey.fields.map { it.name }, `is`(listOf("id")))
324        }.compilesWithoutError().withWarningCount(0)
325    }
326
327    @Test
328    fun notNull() {
329        singleEntity(
330                """
331                @PrimaryKey int id;
332                @NonNull public String name;
333                """
334        ) { entity, _ ->
335            val field = fieldsByName(entity, "name").first()
336            assertThat(field.name, `is`("name"))
337            assertThat(field.columnName, `is`("name"))
338            assertThat(field.nonNull, `is`(true))
339        }.compilesWithoutError()
340    }
341
342    private fun fieldsByName(entity : Pojo, vararg fieldNames : String) : List<Field> {
343        return fieldNames
344                .map { name -> entity.fields.find { it.name == name } }
345                .filterNotNull()
346    }
347
348    @Test
349    fun index_simple() {
350        val annotation = mapOf(
351                "indices" to """@Index("foo")"""
352        )
353        singleEntity(
354                """
355                @PrimaryKey
356                public int id;
357                public String foo;
358                """
359                , annotation) { entity, _ ->
360            assertThat(entity.indices, `is`(
361                    listOf(Index(name = "index_MyEntity_foo",
362                            unique = false,
363                            fields = fieldsByName(entity, "foo")))))
364        }.compilesWithoutError()
365    }
366
367    @Test
368    fun index_fromField() {
369        singleEntity(
370                """
371                @PrimaryKey
372                public int id;
373                @ColumnInfo(index = true)
374                public String foo;
375                """) { entity, _ ->
376            assertThat(entity.indices, `is`(
377                    listOf(Index(name = "index_MyEntity_foo",
378                            unique = false,
379                            fields = fieldsByName(entity, "foo")))
380            ))
381        }.compilesWithoutError()
382    }
383
384    @Test
385    fun index_multiColumn() {
386        val annotation = mapOf(
387                "indices" to """@Index({"foo", "id"})"""
388        )
389        singleEntity(
390                """
391                @PrimaryKey
392                public int id;
393                public String foo;
394                """
395                , annotation) { entity, _ ->
396            assertThat(entity.indices, `is`(
397                    listOf(Index(name = "index_MyEntity_foo_id",
398                            unique = false,
399                            fields = fieldsByName(entity, "foo", "id")))
400            ))
401        }.compilesWithoutError()
402    }
403
404    @Test
405    fun index_multiple() {
406        val annotation = mapOf(
407                "indices" to """{@Index({"foo", "id"}), @Index({"bar_column", "foo"})}"""
408        )
409        singleEntity(
410                """
411                @PrimaryKey
412                public int id;
413                public String foo;
414                @ColumnInfo(name = "bar_column")
415                public String bar;
416                """
417                , annotation) { entity, _ ->
418            assertThat(entity.indices, `is`(
419                    listOf(Index(name = "index_MyEntity_foo_id",
420                            unique = false,
421                            fields = fieldsByName(entity, "foo", "id")),
422                            Index(name = "index_MyEntity_bar_column_foo",
423                                    unique = false,
424                                    fields = fieldsByName(entity, "bar", "foo")))
425            ))
426        }.compilesWithoutError()
427    }
428
429    @Test
430    fun index_unique() {
431        val annotation = mapOf(
432                "indices" to """@Index(value = {"foo", "id"}, unique = true)"""
433        )
434        singleEntity(
435                """
436                @PrimaryKey
437                public int id;
438                public String foo;
439                """
440                , annotation) { entity, _ ->
441            assertThat(entity.indices, `is`(
442                    listOf(Index(name = "index_MyEntity_foo_id",
443                            unique = true,
444                           fields = fieldsByName(entity, "foo", "id")))
445            ))
446        }.compilesWithoutError()
447    }
448
449    @Test
450    fun index_customName() {
451        val annotation = mapOf(
452                "indices" to """@Index(value = {"foo"}, name = "myName")"""
453        )
454        singleEntity(
455                """
456                @PrimaryKey
457                public int id;
458                public String foo;
459                """
460                , annotation) { entity, _ ->
461            assertThat(entity.indices, `is`(
462                    listOf(Index(name = "myName",
463                            unique = false,
464                            fields = fieldsByName(entity, "foo")))
465            ))
466        }.compilesWithoutError()
467    }
468
469    @Test
470    fun index_customTableName() {
471        val annotation = mapOf(
472                "tableName" to "\"MyTable\"",
473                "indices" to """@Index(value = {"foo"})"""
474        )
475        singleEntity(
476                """
477                @PrimaryKey
478                public int id;
479                public String foo;
480                """
481                , annotation) { entity, _ ->
482            assertThat(entity.indices, `is`(
483                    listOf(Index(name = "index_MyTable_foo",
484                            unique = false,
485                            fields = fieldsByName(entity, "foo")))
486            ))
487        }.compilesWithoutError()
488    }
489
490    @Test
491    fun index_empty() {
492        val annotation = mapOf(
493                "indices" to """@Index({})"""
494        )
495        singleEntity(
496                """
497                @PrimaryKey
498                public int id;
499                public String foo;
500                """
501                , annotation) { _, _ ->
502        }.failsToCompile().withErrorContaining(
503                ProcessorErrors.INDEX_COLUMNS_CANNOT_BE_EMPTY
504        )
505    }
506
507    @Test
508    fun index_missingColumn() {
509        val annotation = mapOf(
510                "indices" to """@Index({"foo", "bar"})"""
511        )
512        singleEntity(
513                """
514                @PrimaryKey
515                public int id;
516                public String foo;
517                """
518                , annotation) { _, _ ->
519        }.failsToCompile().withErrorContaining(
520                ProcessorErrors.indexColumnDoesNotExist("bar", listOf("id, foo"))
521        )
522    }
523
524    @Test
525    fun index_nameConflict() {
526        val annotation = mapOf(
527                "indices" to """@Index({"foo"})"""
528        )
529        singleEntity(
530                """
531                @PrimaryKey
532                public int id;
533                @ColumnInfo(index = true)
534                public String foo;
535                """
536                , annotation) { _, _ ->
537        }.failsToCompile().withErrorContaining(
538                ProcessorErrors.duplicateIndexInEntity("index_MyEntity_foo")
539        )
540    }
541
542    @Test
543    fun index_droppedParentFieldIndex() {
544        val parent = JavaFileObjects.forSourceLines("foo.bar.Base",
545                """
546                package foo.bar;
547                import android.arch.persistence.room.*;
548                public class Base {
549                    @PrimaryKey
550                    long baseId;
551                    @ColumnInfo(index = true)
552                    String name;
553                    String lastName;
554                }
555                """)
556        singleEntity(
557                """
558                @PrimaryKey
559                public int id;
560                """, baseClass = "foo.bar.Base", jfos = listOf(parent)) { entity, _ ->
561            assertThat(entity.indices.isEmpty(), `is`(true))
562        }.compilesWithoutError()
563                .withWarningContaining(
564                        ProcessorErrors.droppedSuperClassFieldIndex(
565                                fieldName = "name",
566                                childEntity = "foo.bar.MyEntity",
567                                superEntity = "foo.bar.Base")
568                )
569    }
570
571    @Test
572    fun index_keptGrandParentEntityIndex() {
573        val grandParent = JavaFileObjects.forSourceLines("foo.bar.Base",
574                """
575                package foo.bar;
576                import android.arch.persistence.room.*;
577                @Entity(indices = @Index({"name", "lastName"}))
578                public class Base {
579                    @PrimaryKey
580                    long baseId;
581                    String name, lastName;
582                }
583                """)
584        val parent = JavaFileObjects.forSourceLines("foo.bar.Parent",
585                """
586                package foo.bar;
587                import android.arch.persistence.room.*;
588
589                public class Parent extends Base {
590                    String iHaveAField;
591                }
592                """)
593        singleEntity(
594                """
595                @PrimaryKey
596                public int id;
597                """,
598                baseClass = "foo.bar.Parent",
599                attributes = hashMapOf("inheritSuperIndices" to "true"),
600                jfos = listOf(parent, grandParent)) {
601            entity, _ ->
602            assertThat(entity.indices.size, `is`(1))
603            assertThat(entity.indices.first(),
604                    `is`(Index(name = "index_MyEntity_name_lastName",
605                            unique = false,
606                            fields = fieldsByName(entity, "name", "lastName"))))
607        }.compilesWithoutError().withWarningCount(0)
608    }
609
610    @Test
611    fun index_keptParentEntityIndex() {
612        val parent = JavaFileObjects.forSourceLines("foo.bar.Base",
613                """
614                package foo.bar;
615                import android.arch.persistence.room.*;
616                @Entity(indices = @Index({"name", "lastName"}))
617                public class Base {
618                    @PrimaryKey
619                    long baseId;
620                    String name, lastName;
621                }
622                """)
623        singleEntity(
624                """
625                @PrimaryKey
626                public int id;
627                """,
628                baseClass = "foo.bar.Base",
629                attributes = hashMapOf("inheritSuperIndices" to "true"),
630                jfos = listOf(parent)) { entity, _ ->
631            assertThat(entity.indices.size, `is`(1))
632            assertThat(entity.indices.first(),
633                    `is`(Index(name = "index_MyEntity_name_lastName",
634                            unique = false,
635                            fields = fieldsByName(entity, "name", "lastName"))))
636        }.compilesWithoutError().withWarningCount(0)
637    }
638
639    @Test
640    fun index_keptParentFieldIndex() {
641        val parent = JavaFileObjects.forSourceLines("foo.bar.Base",
642                """
643                package foo.bar;
644                import android.arch.persistence.room.*;
645                public class Base {
646                    @PrimaryKey
647                    long baseId;
648                    @ColumnInfo(index = true)
649                    String name;
650                    String lastName;
651                }
652                """)
653        singleEntity(
654                """
655                @PrimaryKey
656                public int id;
657                """,
658                baseClass = "foo.bar.Base",
659                attributes = hashMapOf("inheritSuperIndices" to "true"),
660                jfos = listOf(parent)) { entity, _ ->
661            assertThat(entity.indices.size, `is`(1))
662            assertThat(entity.indices.first(),
663                    `is`(Index(name = "index_MyEntity_name",
664                            unique = false,
665                            fields = fieldsByName(entity, "name"))))
666        }.compilesWithoutError().withWarningCount(0)
667
668    }
669
670    @Test
671    fun index_droppedGrandParentEntityIndex() {
672        val grandParent = JavaFileObjects.forSourceLines("foo.bar.Base",
673                """
674                package foo.bar;
675                import android.arch.persistence.room.*;
676                @Entity(indices = @Index({"name", "lastName"}))
677                public class Base {
678                    @PrimaryKey
679                    long baseId;
680                    String name, lastName;
681                }
682                """)
683        val parent = JavaFileObjects.forSourceLines("foo.bar.Parent",
684                """
685                package foo.bar;
686                import android.arch.persistence.room.*;
687
688                public class Parent extends Base {
689                    String iHaveAField;
690                }
691                """)
692        singleEntity(
693                """
694                @PrimaryKey
695                public int id;
696                """, baseClass = "foo.bar.Parent", jfos = listOf(parent, grandParent)) {
697            entity, _ ->
698            assertThat(entity.indices.isEmpty(), `is`(true))
699        }.compilesWithoutError()
700                .withWarningContaining(
701                        ProcessorErrors.droppedSuperClassIndex(
702                                childEntity = "foo.bar.MyEntity",
703                                superEntity = "foo.bar.Base")
704                )
705    }
706
707    @Test
708    fun index_droppedParentEntityIndex() {
709        val parent = JavaFileObjects.forSourceLines("foo.bar.Base",
710                """
711                package foo.bar;
712                import android.arch.persistence.room.*;
713                @Entity(indices = @Index({"name", "lastName"}))
714                public class Base {
715                    @PrimaryKey
716                    long baseId;
717                    String name, lastName;
718                }
719                """)
720        singleEntity(
721                """
722                @PrimaryKey
723                public int id;
724                """, baseClass = "foo.bar.Base", jfos = listOf(parent)) { entity, _ ->
725            assertThat(entity.indices.isEmpty(), `is`(true))
726        }.compilesWithoutError()
727                .withWarningContaining(
728                        ProcessorErrors.droppedSuperClassIndex(
729                                childEntity = "foo.bar.MyEntity",
730                                superEntity = "foo.bar.Base")
731                )
732    }
733
734    @Test
735    fun index_droppedEmbeddedEntityIndex() {
736        singleEntity(
737                """
738                @PrimaryKey
739                public int id;
740                @Embedded
741                public Foo foo;
742                @Entity(indices = {@Index("a")})
743                static class Foo {
744                    @PrimaryKey
745                    @ColumnInfo(name = "foo_id")
746                    int id;
747                    @ColumnInfo(index = true)
748                    public int a;
749                }
750                """) { entity, _ ->
751            assertThat(entity.indices.isEmpty(), `is`(true))
752        }.compilesWithoutError()
753                .withWarningContaining(
754                        ProcessorErrors.droppedEmbeddedIndex(
755                                entityName = "foo.bar.MyEntity.Foo",
756                                fieldPath = "foo",
757                                grandParent = "foo.bar.MyEntity")
758                )
759    }
760
761    @Test
762    fun index_onEmbeddedField() {
763        singleEntity(
764                """
765                @PrimaryKey
766                public int id;
767                @Embedded
768                @ColumnInfo(index = true)
769                public Foo foo;
770                static class Foo {
771                    @ColumnInfo(index = true)
772                    public int a;
773                }
774                """) { entity, _ ->
775            assertThat(entity.indices.isEmpty(), `is`(true))
776        }.failsToCompile().withErrorContaining(
777                ProcessorErrors.CANNOT_USE_MORE_THAN_ONE_POJO_FIELD_ANNOTATION
778        )
779    }
780
781    @Test
782    fun index_droppedEmbeddedFieldIndex() {
783        singleEntity(
784                """
785                @PrimaryKey
786                public int id;
787                @Embedded
788                public Foo foo;
789                static class Foo {
790                    @ColumnInfo(index = true)
791                    public int a;
792                }
793                """) { entity, _ ->
794            assertThat(entity.indices.isEmpty(), `is`(true))
795        }.compilesWithoutError()
796                .withWarningContaining(
797                        ProcessorErrors.droppedEmbeddedFieldIndex("foo > a", "foo.bar.MyEntity")
798                )
799    }
800
801    @Test
802    fun index_referenceEmbeddedField() {
803        singleEntity(
804                """
805                @PrimaryKey
806                public int id;
807                @Embedded
808                public Foo foo;
809                static class Foo {
810                    public int a;
811                }
812                """, attributes = mapOf("indices" to "@Index(\"a\")")) { entity, _ ->
813            assertThat(entity.indices.size, `is`(1))
814            assertThat(entity.indices.first(), `is`(
815                    Index(
816                            name = "index_MyEntity_a",
817                            unique = false,
818                            fields = fieldsByName(entity, "a")
819                    )
820            ))
821        }.compilesWithoutError()
822    }
823
824    @Test
825    fun primaryKey_definedInBothWays() {
826        singleEntity(
827                """
828                public int id;
829                @PrimaryKey
830                public String foo;
831                """,
832                attributes = mapOf("primaryKeys" to "\"id\"")) { _, _ ->
833        }.failsToCompile().withErrorContaining(
834                ProcessorErrors.multiplePrimaryKeyAnnotations(
835                        listOf("PrimaryKey[id]", "PrimaryKey[foo]")
836                ))
837    }
838
839    @Test
840    fun primaryKey_badColumnName() {
841        singleEntity(
842                """
843                public int id;
844                """,
845                attributes = mapOf("primaryKeys" to "\"foo\"")) { _, _ ->
846        }.failsToCompile().withErrorContaining(
847                ProcessorErrors.primaryKeyColumnDoesNotExist("foo", listOf("id")))
848    }
849
850    @Test
851    fun primaryKey_multipleAnnotations() {
852        singleEntity("""
853                @PrimaryKey
854                int x;
855                @PrimaryKey
856                int y;
857                """) { entity, _ ->
858            assertThat(entity.primaryKey.fields.isEmpty(), `is`(true))
859        }.failsToCompile()
860                .withErrorContaining(
861                        ProcessorErrors.multiplePrimaryKeyAnnotations(
862                                listOf("PrimaryKey[x]", "PrimaryKey[y]")))
863    }
864
865    @Test
866    fun primaryKey_fromParentField() {
867        val parent = JavaFileObjects.forSourceLines("foo.bar.Base",
868                """
869                package foo.bar;
870                import android.arch.persistence.room.*;
871                public class Base {
872                    @PrimaryKey
873                    long baseId;
874                    String name, lastName;
875                }
876                """)
877        singleEntity(
878                """
879                public int id;
880                """,
881                baseClass = "foo.bar.Base",
882                jfos = listOf(parent)) { entity, _ ->
883            assertThat(entity.primaryKey.fields.firstOrNull()?.name, `is`("baseId"))
884
885        }.compilesWithoutError().withWarningCount(0)
886    }
887
888    @Test
889    fun primaryKey_fromParentEntity() {
890        val parent = JavaFileObjects.forSourceLines("foo.bar.Base",
891                """
892                package foo.bar;
893                import android.arch.persistence.room.*;
894                @Entity(primaryKeys = "baseId")
895                public class Base {
896                    long baseId;
897                    String name, lastName;
898                }
899                """)
900        singleEntity(
901                """
902                public int id;
903                """,
904                baseClass = "foo.bar.Base",
905                jfos = listOf(parent)) { entity, _ ->
906            assertThat(entity.primaryKey.fields.firstOrNull()?.name, `is`("baseId"))
907        }.compilesWithoutError().withWarningCount(0)
908    }
909
910    @Test
911    fun primaryKey_overrideFromParentField() {
912        val parent = JavaFileObjects.forSourceLines("foo.bar.Base",
913                """
914                package foo.bar;
915                import android.arch.persistence.room.*;
916                public class Base {
917                    @PrimaryKey
918                    long baseId;
919                    String name, lastName;
920                }
921                """)
922        singleEntity(
923                """
924                @PrimaryKey
925                public int id;
926                """,
927                baseClass = "foo.bar.Base",
928                jfos = listOf(parent)) { entity, _ ->
929            assertThat(entity.primaryKey.fields.size, `is`(1))
930            assertThat(entity.primaryKey.fields.firstOrNull()?.name, `is`("id"))
931            assertThat(entity.primaryKey.autoGenerateId, `is`(false))
932        }.compilesWithoutError().withNoteContaining(
933                "PrimaryKey[baseId] is overridden by PrimaryKey[id]"
934        )
935    }
936
937    @Test
938    fun primaryKey_overrideFromParentEntityViaField() {
939        val parent = JavaFileObjects.forSourceLines("foo.bar.Base",
940                """
941                package foo.bar;
942                import android.arch.persistence.room.*;
943                @Entity(primaryKeys = "baseId")
944                public class Base {
945                    long baseId;
946                    String name, lastName;
947                }
948                """)
949        singleEntity(
950                """
951                @PrimaryKey
952                public int id;
953                """,
954                baseClass = "foo.bar.Base",
955                jfos = listOf(parent)) { entity, _ ->
956            assertThat(entity.primaryKey.fields.size, `is`(1))
957            assertThat(entity.primaryKey.fields.firstOrNull()?.name, `is`("id"))
958        }.compilesWithoutError().withNoteContaining(
959                "PrimaryKey[baseId] is overridden by PrimaryKey[id]"
960        )
961    }
962
963    @Test
964    fun primaryKey_overrideFromParentEntityViaEntity() {
965        val parent = JavaFileObjects.forSourceLines("foo.bar.Base",
966                """
967                package foo.bar;
968                import android.arch.persistence.room.*;
969                @Entity(primaryKeys = "baseId")
970                public class Base {
971                    long baseId;
972                    String name, lastName;
973                }
974                """)
975        singleEntity(
976                """
977                public int id;
978                """,
979                baseClass = "foo.bar.Base",
980                jfos = listOf(parent),
981                attributes = mapOf("primaryKeys" to "\"id\"")) { entity, _ ->
982            assertThat(entity.primaryKey.fields.size, `is`(1))
983            assertThat(entity.primaryKey.fields.firstOrNull()?.name, `is`("id"))
984            assertThat(entity.primaryKey.autoGenerateId, `is`(false))
985        }.compilesWithoutError().withNoteContaining(
986                "PrimaryKey[baseId] is overridden by PrimaryKey[id]"
987        )
988    }
989
990    @Test
991    fun primaryKey_autoGenerate() {
992        listOf("long", "Long", "Integer", "int").forEach { type ->
993            singleEntity(
994                    """
995                @PrimaryKey(autoGenerate = true)
996                public $type id;
997                """) { entity, _ ->
998                assertThat(entity.primaryKey.fields.size, `is`(1))
999                assertThat(entity.primaryKey.fields.firstOrNull()?.name, `is`("id"))
1000                assertThat(entity.primaryKey.autoGenerateId, `is`(true))
1001            }.compilesWithoutError()
1002        }
1003    }
1004
1005    @Test
1006    fun primaryKey_autoGenerateBadType() {
1007        listOf("String", "float", "Float", "Double", "double").forEach { type ->
1008            singleEntity(
1009                    """
1010                @PrimaryKey(autoGenerate = true)
1011                public $type id;
1012                """) { entity, _ ->
1013                assertThat(entity.primaryKey.fields.size, `is`(1))
1014                assertThat(entity.primaryKey.fields.firstOrNull()?.name, `is`("id"))
1015                assertThat(entity.primaryKey.autoGenerateId, `is`(true))
1016            }.failsToCompile().withErrorContaining(
1017                    ProcessorErrors.AUTO_INCREMENTED_PRIMARY_KEY_IS_NOT_INT)
1018        }
1019    }
1020
1021    @Test
1022    fun primaryKey_embedded(){
1023        singleEntity(
1024                """
1025                public int id;
1026
1027                @Embedded(prefix = "bar_")
1028                @PrimaryKey
1029                @NonNull
1030                public Foo foo;
1031
1032                static class Foo {
1033                    public int a;
1034                    public int b;
1035                }
1036                """) { entity, _ ->
1037            assertThat(entity.primaryKey.fields.map { it.columnName },
1038                    `is`(listOf("bar_a", "bar_b")))
1039        }.compilesWithoutError().withWarningCount(0)
1040    }
1041
1042    @Test
1043    fun primaryKey_embeddedInherited(){
1044        val parent = JavaFileObjects.forSourceLines("foo.bar.Base",
1045                """
1046                package foo.bar;
1047                import android.support.annotation.NonNull;
1048                import android.arch.persistence.room.*;
1049
1050                public class Base {
1051                    long baseId;
1052                    String name, lastName;
1053                    @Embedded(prefix = "bar_")
1054                    @PrimaryKey
1055                    @NonNull
1056                    public Foo foo;
1057
1058                    static class Foo {
1059                        public int a;
1060                        public int b;
1061                    }
1062                }
1063                """)
1064        singleEntity(
1065                """
1066                public int id;
1067                """,
1068                baseClass = "foo.bar.Base",
1069                jfos = listOf(parent)) { entity, _ ->
1070            assertThat(entity.primaryKey.fields.map { it.columnName },
1071                    `is`(listOf("bar_a", "bar_b")))
1072        }.compilesWithoutError().withWarningCount(0)
1073    }
1074
1075    @Test
1076    fun primaryKey_overrideViaEmbedded() {
1077        val parent = JavaFileObjects.forSourceLines("foo.bar.Base",
1078                """
1079                package foo.bar;
1080                import android.arch.persistence.room.*;
1081
1082                @Entity(primaryKeys = "baseId")
1083                public class Base {
1084                    long baseId;
1085                    String name, lastName;
1086                }
1087                """)
1088        singleEntity(
1089                """
1090                public int id;
1091                @Embedded(prefix = "bar_")
1092                @PrimaryKey
1093                @NonNull
1094                public Foo foo;
1095
1096                static class Foo {
1097                    public int a;
1098                    public int b;
1099                }
1100                """,
1101                baseClass = "foo.bar.Base",
1102                jfos = listOf(parent)) { entity, _ ->
1103            assertThat(entity.primaryKey.fields.map { it.columnName },
1104                    `is`(listOf("bar_a", "bar_b")))
1105        }.compilesWithoutError().withNoteContaining(
1106                "PrimaryKey[baseId] is overridden by PrimaryKey[foo > a, foo > b]")
1107    }
1108
1109    @Test
1110    fun primaryKey_overrideEmbedded() {
1111        val parent = JavaFileObjects.forSourceLines("foo.bar.Base",
1112                """
1113                package foo.bar;
1114                import android.support.annotation.NonNull;
1115                import android.arch.persistence.room.*;
1116
1117                public class Base {
1118                    long baseId;
1119                    String name, lastName;
1120                    @Embedded(prefix = "bar_")
1121                    @PrimaryKey
1122                    @NonNull
1123                    public Foo foo;
1124
1125                    static class Foo {
1126                        public int a;
1127                        public int b;
1128                    }
1129                }
1130                """)
1131        singleEntity(
1132                """
1133                @PrimaryKey
1134                public int id;
1135                """,
1136                baseClass = "foo.bar.Base",
1137                jfos = listOf(parent)) { entity, _ ->
1138            assertThat(entity.primaryKey.fields.map { it.columnName },
1139                    `is`(listOf("id")))
1140        }.compilesWithoutError().withNoteContaining(
1141                "PrimaryKey[foo > a, foo > b] is overridden by PrimaryKey[id]")
1142    }
1143
1144    @Test
1145    fun primaryKey_NonNull() {
1146        singleEntity(
1147                """
1148            @PrimaryKey
1149            @NonNull
1150            public String id;
1151            """) { entity, _ ->
1152            assertThat(entity.primaryKey.fields.size, `is`(1))
1153            assertThat(entity.primaryKey.fields.firstOrNull()?.name, `is`("id"))
1154        }.compilesWithoutError()
1155    }
1156
1157    @Test
1158    fun primaryKey_Nullable() {
1159        singleEntity(
1160                """
1161            @PrimaryKey
1162            public String id;
1163            """) { entity, _ ->
1164            assertThat(entity.primaryKey.fields.size, `is`(1))
1165            assertThat(entity.primaryKey.fields.firstOrNull()?.name, `is`("id"))
1166        }.failsToCompile().withErrorContaining(PRIMARY_KEY_NULL)
1167    }
1168
1169    @Test
1170    fun primaryKey_MultipleNullable() {
1171        singleEntity(
1172                """
1173            @PrimaryKey
1174            public String id;
1175            @PrimaryKey
1176            public String anotherId;
1177            """) { entity, _ ->
1178        }.failsToCompile().withErrorContaining(PRIMARY_KEY_NULL)
1179    }
1180
1181    @Test
1182    fun primaryKey_MultipleNullableAndNonNullable() {
1183        singleEntity(
1184                """
1185            @PrimaryKey
1186            @NonNull
1187            public String id;
1188            @PrimaryKey
1189            public String anotherId;
1190            """) { entity, _ ->
1191        }.failsToCompile().withErrorContaining(PRIMARY_KEY_NULL)
1192    }
1193
1194    @Test
1195    fun primaryKey_definedAsAttributesNullable() {
1196        singleEntity(
1197                """
1198                public int id;
1199                public String foo;
1200                """,
1201                attributes = mapOf("primaryKeys" to "{\"id\", \"foo\"}")) { _, _ ->
1202        }.failsToCompile().withErrorContaining(PRIMARY_KEY_NULL)
1203    }
1204
1205    @Test
1206    fun primaryKey_definedAsAttributesNonNull() {
1207        singleEntity(
1208                """
1209                public int id;
1210                @NonNull
1211                public String foo;
1212                """,
1213                attributes = mapOf("primaryKeys" to "{\"id\", \"foo\"}")) { entity, _ ->
1214            assertThat(entity.primaryKey.fields.map { it.name }, `is`(listOf("id", "foo")))
1215        }.compilesWithoutError()
1216    }
1217
1218    @Test
1219    fun relationInEntity() {
1220        singleEntity(
1221                """
1222                @PrimaryKey
1223                int id;
1224                @Relation(parentColumn = "id", entityColumn = "uid")
1225                java.util.List<User> users;
1226                """, jfos = listOf(COMMON.USER)
1227        ) { _, _ ->
1228        }.failsToCompile().withErrorContaining(RELATION_IN_ENTITY)
1229    }
1230
1231    @Test
1232    fun foreignKey_invalidAction() {
1233        val annotation = mapOf(
1234                "foreignKeys" to """{@ForeignKey(
1235                    entity = ${COMMON.USER_TYPE_NAME}.class,
1236                    parentColumns = "lastName",
1237                    childColumns = "name",
1238                    onDelete = 101
1239                )}""".trimIndent()
1240        )
1241        singleEntity(
1242                """
1243                @PrimaryKey
1244                int id;
1245                String name;
1246                """,
1247                attributes = annotation, jfos = listOf(COMMON.USER)
1248        ){ _, _ ->
1249        }.failsToCompile().withErrorContaining(ProcessorErrors.INVALID_FOREIGN_KEY_ACTION)
1250    }
1251
1252    @Test
1253    fun foreignKey_badEntity() {
1254        val annotation = mapOf(
1255                "foreignKeys" to """{@ForeignKey(
1256                    entity = dsa.class,
1257                    parentColumns = "lastName",
1258                    childColumns = "name"
1259                )}""".trimIndent()
1260        )
1261        singleEntity(
1262                """
1263                @PrimaryKey
1264                int id;
1265                String name;
1266                """,
1267                attributes = annotation, jfos = listOf(COMMON.USER)
1268        ){ _, _ ->
1269        }.failsToCompile().withErrorContaining("cannot find symbol")
1270    }
1271
1272    @Test
1273    fun foreignKey_notAnEntity() {
1274        val annotation = mapOf(
1275                "foreignKeys" to """{@ForeignKey(
1276                    entity = ${COMMON.NOT_AN_ENTITY_TYPE_NAME}.class,
1277                    parentColumns = "lastName",
1278                    childColumns = "name"
1279                )}""".trimIndent()
1280        )
1281        singleEntity(
1282                """
1283                @PrimaryKey
1284                int id;
1285                String name;
1286                """,
1287                attributes = annotation, jfos = listOf(COMMON.NOT_AN_ENTITY)
1288        ){ _, _ ->
1289        }.failsToCompile().withErrorContaining(ProcessorErrors.foreignKeyNotAnEntity(
1290                COMMON.NOT_AN_ENTITY_TYPE_NAME.toString()))
1291    }
1292
1293    @Test
1294    fun foreignKey_invalidChildColumn() {
1295        val annotation = mapOf(
1296                "foreignKeys" to """{@ForeignKey(
1297                    entity = ${COMMON.USER_TYPE_NAME}.class,
1298                    parentColumns = "lastName",
1299                    childColumns = "namex"
1300                )}""".trimIndent()
1301        )
1302        singleEntity(
1303                """
1304                @PrimaryKey
1305                int id;
1306                String name;
1307                """,
1308                attributes = annotation, jfos = listOf(COMMON.USER)
1309        ){ _, _ ->
1310        }.failsToCompile().withErrorContaining(ProcessorErrors.foreignKeyChildColumnDoesNotExist(
1311                "namex", listOf("id", "name")))
1312    }
1313
1314    @Test
1315    fun foreignKey_columnCountMismatch() {
1316        val annotation = mapOf(
1317                "foreignKeys" to """{@ForeignKey(
1318                    entity = ${COMMON.USER_TYPE_NAME}.class,
1319                    parentColumns = "lastName",
1320                    childColumns = {"name", "id"}
1321                )}""".trimIndent()
1322        )
1323        singleEntity(
1324                """
1325                @PrimaryKey
1326                int id;
1327                String name;
1328                """,
1329                attributes = annotation, jfos = listOf(COMMON.USER)
1330        ){ _, _ ->
1331        }.failsToCompile().withErrorContaining(ProcessorErrors.foreignKeyColumnNumberMismatch(
1332                listOf("name", "id"), listOf("lastName")))
1333    }
1334
1335    @Test
1336    fun foreignKey_emptyChildColumns() {
1337        val annotation = mapOf(
1338                "foreignKeys" to """{@ForeignKey(
1339                    entity = ${COMMON.USER_TYPE_NAME}.class,
1340                    parentColumns = "lastName",
1341                    childColumns = {}
1342                )}""".trimIndent()
1343        )
1344        singleEntity(
1345                """
1346                @PrimaryKey
1347                int id;
1348                String name;
1349                """,
1350                attributes = annotation, jfos = listOf(COMMON.USER)
1351        ){ _, _ ->
1352        }.failsToCompile().withErrorContaining(ProcessorErrors.FOREIGN_KEY_EMPTY_CHILD_COLUMN_LIST)
1353    }
1354
1355    @Test
1356    fun foreignKey_emptyParentColumns() {
1357        val annotation = mapOf(
1358                "foreignKeys" to """{@ForeignKey(
1359                    entity = ${COMMON.USER_TYPE_NAME}.class,
1360                    parentColumns = {},
1361                    childColumns = {"name"}
1362                )}""".trimIndent()
1363        )
1364        singleEntity(
1365                """
1366                @PrimaryKey
1367                int id;
1368                String name;
1369                """,
1370                attributes = annotation, jfos = listOf(COMMON.USER)
1371        ){ _, _ ->
1372        }.failsToCompile().withErrorContaining(ProcessorErrors.FOREIGN_KEY_EMPTY_PARENT_COLUMN_LIST)
1373    }
1374
1375    @Test
1376    fun foreignKey_simple() {
1377        val annotation = mapOf(
1378                "foreignKeys" to """{@ForeignKey(
1379                    entity = ${COMMON.USER_TYPE_NAME}.class,
1380                    parentColumns = "lastName",
1381                    childColumns = "name",
1382                    onDelete = ForeignKey.SET_NULL,
1383                    onUpdate = ForeignKey.CASCADE,
1384                    deferred = true
1385                )}""".trimIndent()
1386        )
1387        singleEntity(
1388                """
1389                @PrimaryKey
1390                int id;
1391                String name;
1392                """,
1393                attributes = annotation, jfos = listOf(COMMON.USER)
1394        ){ entity, _ ->
1395            assertThat(entity.foreignKeys.size, `is`(1))
1396            val fKey = entity.foreignKeys.first()
1397            assertThat(fKey.parentTable, `is`("User"))
1398            assertThat(fKey.parentColumns, `is`(listOf("lastName")))
1399            assertThat(fKey.deferred, `is`(true))
1400            assertThat(fKey.childFields.size, `is`(1))
1401            val field = fKey.childFields.first()
1402            assertThat(field.name, `is`("name"))
1403        }.compilesWithoutError()
1404    }
1405
1406    @Test
1407    fun foreignKey_dontDuplicationChildIndex_SingleColumn() {
1408        val annotation = mapOf(
1409                "foreignKeys" to """{@ForeignKey(
1410                    entity = ${COMMON.USER_TYPE_NAME}.class,
1411                    parentColumns = "lastName",
1412                    childColumns = "name",
1413                    onDelete = ForeignKey.SET_NULL,
1414                    onUpdate = ForeignKey.CASCADE,
1415                    deferred = true
1416                )}""".trimIndent(),
1417                "indices" to """@Index("name")"""
1418        )
1419        singleEntity(
1420                """
1421                @PrimaryKey
1422                int id;
1423                String name;
1424                """,
1425                attributes = annotation, jfos = listOf(COMMON.USER)
1426        ) { _, _ ->
1427        }.compilesWithoutWarnings()
1428    }
1429
1430    @Test
1431    fun foreignKey_dontDuplicationChildIndex_MultipleColumns() {
1432        val annotation = mapOf(
1433                "foreignKeys" to """{@ForeignKey(
1434                    entity = ${COMMON.USER_TYPE_NAME}.class,
1435                    parentColumns = {"lastName", "name"},
1436                    childColumns = {"lName", "name"},
1437                    onDelete = ForeignKey.SET_NULL,
1438                    onUpdate = ForeignKey.CASCADE,
1439                    deferred = true
1440                )}""".trimIndent(),
1441                "indices" to """@Index({"lName", "name"})"""
1442        )
1443        singleEntity(
1444                """
1445                @PrimaryKey
1446                int id;
1447                String name;
1448                String lName;
1449                """,
1450                attributes = annotation, jfos = listOf(COMMON.USER)
1451        ) { entity, _ ->
1452            assertThat(entity.indices.size, `is`(1))
1453        }.compilesWithoutWarnings()
1454    }
1455
1456    @Test
1457    fun foreignKey_dontDuplicationChildIndex_WhenCovered() {
1458        val annotation = mapOf(
1459                "foreignKeys" to """{@ForeignKey(
1460                    entity = ${COMMON.USER_TYPE_NAME}.class,
1461                    parentColumns = {"lastName"},
1462                    childColumns = {"name"},
1463                    onDelete = ForeignKey.SET_NULL,
1464                    onUpdate = ForeignKey.CASCADE,
1465                    deferred = true
1466                )}""".trimIndent(),
1467                "indices" to """@Index({"name", "lName"})"""
1468        )
1469        singleEntity(
1470                """
1471                @PrimaryKey
1472                int id;
1473                String name;
1474                String lName;
1475                """,
1476                attributes = annotation, jfos = listOf(COMMON.USER)
1477        ) { entity, _ ->
1478            assertThat(entity.indices.size, `is`(1))
1479        }.compilesWithoutWarnings()
1480    }
1481
1482    @Test
1483    fun foreignKey_warnMissingChildIndex() {
1484        val annotation = mapOf(
1485                "foreignKeys" to """{@ForeignKey(
1486                    entity = ${COMMON.USER_TYPE_NAME}.class,
1487                    parentColumns = "lastName",
1488                    childColumns = "name",
1489                    onDelete = ForeignKey.SET_NULL,
1490                    onUpdate = ForeignKey.CASCADE,
1491                    deferred = true
1492                )}""".trimIndent()
1493        )
1494        singleEntity(
1495                """
1496                @PrimaryKey
1497                int id;
1498                String name;
1499                """,
1500                attributes = annotation, jfos = listOf(COMMON.USER)
1501        ){ entity, _ ->
1502            assertThat(entity.indices, `is`(emptyList()))
1503        }.compilesWithoutError().withWarningContaining(
1504                ProcessorErrors.foreignKeyMissingIndexInChildColumn("name"))
1505    }
1506
1507    @Test
1508    fun foreignKey_warnMissingChildrenIndex() {
1509        val annotation = mapOf(
1510                "foreignKeys" to """{@ForeignKey(
1511                    entity = ${COMMON.USER_TYPE_NAME}.class,
1512                    parentColumns = {"lastName", "name"},
1513                    childColumns = {"lName", "name"}
1514                )}""".trimIndent()
1515        )
1516        singleEntity(
1517                """
1518                @PrimaryKey
1519                int id;
1520                String name;
1521                String lName;
1522                """,
1523                attributes = annotation, jfos = listOf(COMMON.USER)
1524        ){ entity, _ ->
1525            assertThat(entity.indices, `is`(emptyList()))
1526        }.compilesWithoutError().withWarningContaining(
1527                ProcessorErrors.foreignKeyMissingIndexInChildColumns(listOf("lName", "name")))
1528    }
1529
1530    @Test
1531    fun foreignKey_dontIndexIfAlreadyPrimaryKey() {
1532        val annotation = mapOf(
1533                "foreignKeys" to """{@ForeignKey(
1534                    entity = ${COMMON.USER_TYPE_NAME}.class,
1535                    parentColumns = "lastName",
1536                    childColumns = "id",
1537                    onDelete = ForeignKey.SET_NULL,
1538                    onUpdate = ForeignKey.CASCADE,
1539                    deferred = true
1540                )}""".trimIndent()
1541        )
1542        singleEntity(
1543                """
1544                @PrimaryKey
1545                int id;
1546                String name;
1547                """,
1548                attributes = annotation, jfos = listOf(COMMON.USER)
1549        ){ entity, _ ->
1550            assertThat(entity.indices, `is`(emptyList()))
1551        }.compilesWithoutWarnings()
1552    }
1553}
1554