ForeignKeyTest.java revision 6be69eb5aa66706ff5880e12c17ea6e62c35eda3
10045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar/*
20045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar * Copyright (C) 2017 The Android Open Source Project
30045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar *
40045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
50045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar * you may not use this file except in compliance with the License.
60045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar * You may obtain a copy of the License at
70045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar *
80045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
90045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar *
100045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar * Unless required by applicable law or agreed to in writing, software
110045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
120045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar * See the License for the specific language governing permissions and
140045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar * limitations under the License.
150045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar */
160045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
1764db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarpackage android.arch.persistence.room.integration.testapp.test;
180045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
1924b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Arakiimport static org.hamcrest.CoreMatchers.both;
200045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyarimport static org.hamcrest.CoreMatchers.containsString;
2124b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Arakiimport static org.hamcrest.CoreMatchers.either;
220045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyarimport static org.hamcrest.CoreMatchers.equalTo;
230045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyarimport static org.hamcrest.CoreMatchers.instanceOf;
240045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyarimport static org.hamcrest.CoreMatchers.notNullValue;
250045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyarimport static org.hamcrest.CoreMatchers.nullValue;
260045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyarimport static org.hamcrest.MatcherAssert.assertThat;
2724b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Arakiimport static org.hamcrest.core.Is.is;
280045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
2964db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.Dao;
3064db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.Database;
3164db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.Delete;
3264db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.Entity;
3364db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ForeignKey;
3464db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.Ignore;
3564db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.Index;
3664db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.Insert;
3764db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.PrimaryKey;
3864db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.Query;
3964db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.Room;
4064db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.RoomDatabase;
413542101509120586bbae17b1f748f302e1fb82a3Yigit Boyarimport android.database.sqlite.SQLiteException;
423542101509120586bbae17b1f748f302e1fb82a3Yigit Boyarimport android.support.test.InstrumentationRegistry;
433542101509120586bbae17b1f748f302e1fb82a3Yigit Boyarimport android.support.test.filters.SmallTest;
443542101509120586bbae17b1f748f302e1fb82a3Yigit Boyarimport android.support.test.runner.AndroidJUnit4;
450045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
4624b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Arakiimport org.hamcrest.Matcher;
470045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyarimport org.junit.Before;
480045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyarimport org.junit.Test;
490045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyarimport org.junit.runner.RunWith;
500045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
5136023a6ffdcc24a64c3f86efd4e754cfc3493761Yigit Boyarimport java.util.Locale;
5236023a6ffdcc24a64c3f86efd4e754cfc3493761Yigit Boyar
530045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar@RunWith(AndroidJUnit4.class)
540045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar@SmallTest
550045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyarpublic class ForeignKeyTest {
560045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @Database(version = 1, entities = {A.class, B.class, C.class, D.class, E.class},
570045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            exportSchema = false)
580045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    abstract static class ForeignKeyDb extends RoomDatabase {
590045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        abstract FkDao dao();
600045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
610045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
620045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @SuppressWarnings({"SqlNoDataSourceInspection", "SameParameterValue"})
630045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @Dao
640045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    interface FkDao {
650045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        @Insert
660045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        void insert(A... a);
670045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
680045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        @Insert
690045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        void insert(B... b);
700045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
710045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        @Insert
720045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        void insert(C... c);
730045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
740045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        @Insert
750045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        void insert(D... d);
760045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
773542101509120586bbae17b1f748f302e1fb82a3Yigit Boyar        @Query("SELECT * FROM A WHERE id = :id")
780045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        A loadA(int id);
790045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
803542101509120586bbae17b1f748f302e1fb82a3Yigit Boyar        @Query("SELECT * FROM B WHERE id = :id")
810045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        B loadB(int id);
820045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
833542101509120586bbae17b1f748f302e1fb82a3Yigit Boyar        @Query("SELECT * FROM C WHERE id = :id")
840045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        C loadC(int id);
850045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
863542101509120586bbae17b1f748f302e1fb82a3Yigit Boyar        @Query("SELECT * FROM D WHERE id = :id")
870045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        D loadD(int id);
880045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
893542101509120586bbae17b1f748f302e1fb82a3Yigit Boyar        @Query("SELECT * FROM E WHERE id = :id")
900045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        E loadE(int id);
910045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
920045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        @Delete
930045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        void delete(A... a);
940045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
950045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        @Delete
960045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        void delete(B... b);
970045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
980045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        @Delete
990045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        void delete(C... c);
1000045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
1010045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        @Query("UPDATE A SET name = :newName WHERE id = :id")
1020045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        void changeNameA(int id, String newName);
1030045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
1040045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        @Insert
1050045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        void insert(E... e);
1060045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
1070045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
1080045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
1090045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
1100045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @Entity(indices = {@Index(value = "name", unique = true),
1110045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            @Index(value = {"name", "lastName"}, unique = true)})
1120045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    static class A {
1130045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        @PrimaryKey(autoGenerate = true)
1140045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        public int id;
1150045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        public String name;
1160045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        public String lastName;
1170045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
1180045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        A(String name) {
1190045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            this.name = name;
1200045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        }
1210045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
122f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        @Ignore
1230045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        A(String name, String lastName) {
1240045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            this.name = name;
1250045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            this.lastName = lastName;
1260045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        }
1270045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
1280045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
1290045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @SuppressWarnings("WeakerAccess")
1300045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @Entity(foreignKeys = {
1310045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            @ForeignKey(entity = A.class,
1320045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                    parentColumns = "name",
1330045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                    childColumns = "aName")})
1340045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
1350045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    static class B {
1360045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        @PrimaryKey(autoGenerate = true)
1370045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        public int id;
1380045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        public String aName;
1390045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
1400045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        B(String aName) {
1410045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            this.aName = aName;
1420045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        }
1430045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
1440045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
1450045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @SuppressWarnings("WeakerAccess")
1460045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @Entity(foreignKeys = {
1470045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            @ForeignKey(entity = A.class,
1480045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                    parentColumns = "name",
1490045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                    childColumns = "aName",
1500045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                    deferred = true)})
1510045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    static class C {
1520045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        @PrimaryKey(autoGenerate = true)
1530045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        public int id;
1540045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        public String aName;
1550045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
1560045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        C(String aName) {
1570045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            this.aName = aName;
1580045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        }
1590045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
1600045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
1610045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @SuppressWarnings("WeakerAccess")
1620045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @Entity(foreignKeys = {
1630045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            @ForeignKey(entity = A.class,
1640045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                    parentColumns = "name",
1650045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                    childColumns = "aName",
1660045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                    onDelete = ForeignKey.CASCADE,
1670045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                    onUpdate = ForeignKey.CASCADE)})
1680045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    static class D {
1690045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        @PrimaryKey(autoGenerate = true)
1700045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        public int id;
1710045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        public String aName;
1720045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
1730045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        D(String aName) {
1740045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            this.aName = aName;
1750045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        }
1760045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
1770045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
1780045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @SuppressWarnings("WeakerAccess")
1790045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @Entity(foreignKeys = {
1800045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            @ForeignKey(entity = A.class,
1810045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                    parentColumns = {"name", "lastName"},
1820045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                    childColumns = {"aName", "aLastName"},
1830045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                    onDelete = ForeignKey.SET_NULL,
1840045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                    onUpdate = ForeignKey.CASCADE)})
1850045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    static class E {
1860045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        @PrimaryKey(autoGenerate = true)
1870045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        public int id;
1880045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        public String aName;
1890045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        public String aLastName;
1900045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
1910045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        E() {
1920045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        }
1930045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
194f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar        @Ignore
1950045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        E(String aName, String aLastName) {
1960045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            this.aName = aName;
1970045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            this.aLastName = aLastName;
1980045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        }
1990045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
2000045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
2010045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
2020045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    private ForeignKeyDb mDb;
2030045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    private FkDao mDao;
2040045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
2050045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @Before
2060045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    public void openDb() {
2076be69eb5aa66706ff5880e12c17ea6e62c35eda3Yuichi Araki        mDb = Room.inMemoryDatabaseBuilder(InstrumentationRegistry.getTargetContext(),
2080045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                ForeignKeyDb.class).build();
2090045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        mDao = mDb.dao();
2100045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
2110045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
2120045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @Test
2130045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    public void simpleForeignKeyFailure() {
2140045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        Throwable t = catchException(new ThrowingRunnable() {
2150045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            @Override
2160045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            public void run() throws Exception {
2170045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                mDao.insert(new B("foo"));
2180045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            }
2190045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        });
2200045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        assertThat(t, instanceOf(SQLiteException.class));
22124b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Araki        assertThat(t.getMessage().toUpperCase(Locale.US), is(foreignKeyErrorMessage()));
2220045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
2230045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
2240045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @Test
2250045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    public void simpleForeignKeyDeferredFailure() {
2260045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        Throwable t = catchException(new ThrowingRunnable() {
2270045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            @Override
2280045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            public void run() throws Exception {
2290045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                mDao.insert(new C("foo"));
2300045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            }
2310045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        });
2320045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        assertThat(t, instanceOf(SQLiteException.class));
23324b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Araki        assertThat(t.getMessage().toUpperCase(Locale.US), is(foreignKeyErrorMessage()));
2340045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
2350045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
2360045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @Test
2370045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    public void immediateForeignKeyFailure() {
2380045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        Throwable t = catchException(new ThrowingRunnable() {
2390045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            @Override
2400045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            public void run() throws Exception {
2410045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                try {
2420045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                    mDb.beginTransaction();
2430045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                    mDao.insert(new B("foo"));
2440045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                    mDao.insert(new A("foo"));
2450045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                    mDb.setTransactionSuccessful();
2460045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                } finally {
2470045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                    mDb.endTransaction();
2480045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                }
2490045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            }
2500045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        });
2510045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        assertThat(t, instanceOf(SQLiteException.class));
2520045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
2530045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
2540045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @Test
2550045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    public void deferredForeignKeySuccess() {
2560045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        try {
2570045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            mDb.beginTransaction();
2580045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            mDao.insert(new C("foo"));
2590045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            mDao.insert(new A("foo"));
2600045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            mDb.setTransactionSuccessful();
2610045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        } finally {
2620045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            mDb.endTransaction();
2630045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        }
2640045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        assertThat(mDao.loadA(1), notNullValue());
2650045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        assertThat(mDao.loadC(1), notNullValue());
2660045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
2670045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
2680045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @Test
2690045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    public void onDelete_noAction() {
2700045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        mDao.insert(new A("a1"));
2710045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        final A a = mDao.loadA(1);
2720045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        mDao.insert(new B("a1"));
2730045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        Throwable t = catchException(new ThrowingRunnable() {
2740045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            @Override
2750045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            public void run() throws Exception {
2760045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                mDao.delete(a);
2770045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            }
2780045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        });
2790045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        assertThat(t, instanceOf(SQLiteException.class));
28024b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Araki        assertThat(t.getMessage().toUpperCase(Locale.US), is(foreignKeyErrorMessage()));
2810045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
2820045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
2830045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @Test
2840045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    public void onDelete_noAction_withTransaction() {
2850045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        mDao.insert(new A("a1"));
2860045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        final A a = mDao.loadA(1);
2870045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        mDao.insert(new B("a1"));
2880045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        final B b = mDao.loadB(1);
2890045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        Throwable t = catchException(new ThrowingRunnable() {
2900045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            @Override
2910045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            public void run() throws Exception {
2920045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                deleteInTransaction(a, b);
2930045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            }
2940045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        });
2950045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        assertThat(t, instanceOf(SQLiteException.class));
29624b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Araki        assertThat(t.getMessage().toUpperCase(Locale.US), is(foreignKeyErrorMessage()));
2970045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
2980045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
2990045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @Test
3000045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    public void onDelete_noAction_deferred() {
3010045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        mDao.insert(new A("a1"));
3020045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        final A a = mDao.loadA(1);
3030045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        mDao.insert(new C("a1"));
3040045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        Throwable t = catchException(new ThrowingRunnable() {
3050045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            @Override
3060045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            public void run() throws Exception {
3070045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                mDao.delete(a);
3080045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            }
3090045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        });
3100045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        assertThat(t, instanceOf(SQLiteException.class));
31124b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Araki        assertThat(t.getMessage().toUpperCase(Locale.US), is(foreignKeyErrorMessage()));
3120045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
3130045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
3140045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @Test
3150045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    public void onDelete_noAction__deferredWithTransaction() {
3160045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        mDao.insert(new A("a1"));
3170045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        final A a = mDao.loadA(1);
3180045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        mDao.insert(new C("a1"));
3190045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        final C c = mDao.loadC(1);
3200045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        deleteInTransaction(a, c);
3210045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
3220045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
3230045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @Test
3240045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    public void onDelete_cascade() {
3250045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        mDao.insert(new A("a1"));
3260045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        final A a = mDao.loadA(1);
3270045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        mDao.insert(new D("a1"));
3280045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        final D d = mDao.loadD(1);
3290045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        assertThat("test sanity", d, notNullValue());
3300045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        mDao.delete(a);
3310045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        assertThat(mDao.loadD(1), nullValue());
3320045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
3330045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
3340045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @Test
3350045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    public void onUpdate_cascade() {
3360045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        mDao.insert(new A("a1"));
3370045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        mDao.insert(new D("a1"));
3380045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        final D d = mDao.loadD(1);
3390045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        assertThat("test sanity", d, notNullValue());
3400045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        mDao.changeNameA(1, "bla");
3410045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        assertThat(mDao.loadD(1).aName, equalTo("bla"));
3420045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        assertThat(mDao.loadA(1).name, equalTo("bla"));
3430045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
3440045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
3450045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @Test
3460045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    public void multipleReferences() {
3470045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        mDao.insert(new A("a1", "a2"));
3480045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        final A a = mDao.loadA(1);
3490045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        assertThat("test sanity", a, notNullValue());
3500045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        Throwable t = catchException(new ThrowingRunnable() {
3510045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            @Override
3520045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            public void run() throws Exception {
3530045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                mDao.insert(new E("a1", "dsa"));
3540045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            }
3550045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        });
35624b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Araki        assertThat(t.getMessage().toUpperCase(Locale.US), is(foreignKeyErrorMessage()));
3570045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
3580045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
3590045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @Test
3600045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    public void onDelete_setNull_multipleReferences() {
3610045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        mDao.insert(new A("a1", "a2"));
3620045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        final A a = mDao.loadA(1);
3630045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        mDao.insert(new E("a1", "a2"));
3640045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        assertThat(mDao.loadE(1), notNullValue());
3650045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        mDao.delete(a);
3660045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        E e = mDao.loadE(1);
3670045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        assertThat(e, notNullValue());
3680045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        assertThat(e.aName, nullValue());
3690045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        assertThat(e.aLastName, nullValue());
3700045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
3710045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
3720045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @Test
3730045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    public void onUpdate_cascade_multipleReferences() {
3740045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        mDao.insert(new A("a1", "a2"));
3750045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        final A a = mDao.loadA(1);
3760045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        mDao.insert(new E("a1", "a2"));
3770045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        assertThat(mDao.loadE(1), notNullValue());
3780045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        mDao.changeNameA(1, "foo");
3790045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        assertThat(mDao.loadE(1), notNullValue());
3800045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        assertThat(mDao.loadE(1).aName, equalTo("foo"));
3810045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        assertThat(mDao.loadE(1).aLastName, equalTo("a2"));
3820045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
3830045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
38424b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Araki    private static Matcher<String> foreignKeyErrorMessage() {
38524b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Araki        return either(containsString("FOREIGN KEY"))
38624b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Araki                .or(both(containsString("CODE 19")).and(containsString("CONSTRAINT FAILED")));
38724b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Araki    }
38824b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Araki
3890045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @SuppressWarnings("Duplicates")
3900045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    private void deleteInTransaction(A a, B b) {
3910045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        mDb.beginTransaction();
3920045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        try {
3930045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            mDao.delete(a);
3940045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            mDao.delete(b);
3950045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            mDb.setTransactionSuccessful();
3960045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        } finally {
3970045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            mDb.endTransaction();
3980045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        }
3990045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
4000045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
4010045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    @SuppressWarnings("Duplicates")
4020045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    private void deleteInTransaction(A a, C c) {
4030045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        mDb.beginTransaction();
4040045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        try {
4050045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            mDao.delete(a);
4060045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            mDao.delete(c);
4070045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            mDb.setTransactionSuccessful();
4080045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        } finally {
4090045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            mDb.endTransaction();
4100045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        }
4110045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
4120045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
4130045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    private static Throwable catchException(ThrowingRunnable throwingRunnable) {
4140045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        try {
4150045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            throwingRunnable.run();
4160045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        } catch (Throwable t) {
4170045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            return t;
4180045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        }
4190045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        throw new RuntimeException("didn't throw an exception");
4200045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
4210045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar
4220045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    private interface ThrowingRunnable {
4230045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar        void run() throws Exception;
4240045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar    }
4250045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar}
426