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 17bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viverettepackage androidx.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 293542101509120586bbae17b1f748f302e1fb82a3Yigit Boyarimport android.database.sqlite.SQLiteException; 303542101509120586bbae17b1f748f302e1fb82a3Yigit Boyarimport android.support.test.InstrumentationRegistry; 313542101509120586bbae17b1f748f302e1fb82a3Yigit Boyarimport android.support.test.filters.SmallTest; 323542101509120586bbae17b1f748f302e1fb82a3Yigit Boyarimport android.support.test.runner.AndroidJUnit4; 330045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 34bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.Dao; 35bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.Database; 36bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.Delete; 37bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.Entity; 38bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.ForeignKey; 39bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.Ignore; 40bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.Index; 41bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.Insert; 42bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.PrimaryKey; 43bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.Query; 44bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.Room; 45bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.RoomDatabase; 46bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viverette 4724b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Arakiimport org.hamcrest.Matcher; 480045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyarimport org.junit.Before; 490045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyarimport org.junit.Test; 500045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyarimport org.junit.runner.RunWith; 510045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 5236023a6ffdcc24a64c3f86efd4e754cfc3493761Yigit Boyarimport java.util.Locale; 5336023a6ffdcc24a64c3f86efd4e754cfc3493761Yigit Boyar 540045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar@RunWith(AndroidJUnit4.class) 550045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar@SmallTest 560045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyarpublic class ForeignKeyTest { 570045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Database(version = 1, entities = {A.class, B.class, C.class, D.class, E.class}, 580045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar exportSchema = false) 590045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar abstract static class ForeignKeyDb extends RoomDatabase { 600045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar abstract FkDao dao(); 610045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 620045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 630045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @SuppressWarnings({"SqlNoDataSourceInspection", "SameParameterValue"}) 640045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Dao 650045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar interface FkDao { 660045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Insert 670045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar void insert(A... a); 680045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 690045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Insert 700045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar void insert(B... b); 710045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 720045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Insert 730045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar void insert(C... c); 740045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 750045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Insert 760045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar void insert(D... d); 770045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 783542101509120586bbae17b1f748f302e1fb82a3Yigit Boyar @Query("SELECT * FROM A WHERE id = :id") 790045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar A loadA(int id); 800045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 813542101509120586bbae17b1f748f302e1fb82a3Yigit Boyar @Query("SELECT * FROM B WHERE id = :id") 820045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar B loadB(int id); 830045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 843542101509120586bbae17b1f748f302e1fb82a3Yigit Boyar @Query("SELECT * FROM C WHERE id = :id") 850045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar C loadC(int id); 860045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 873542101509120586bbae17b1f748f302e1fb82a3Yigit Boyar @Query("SELECT * FROM D WHERE id = :id") 880045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar D loadD(int id); 890045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 903542101509120586bbae17b1f748f302e1fb82a3Yigit Boyar @Query("SELECT * FROM E WHERE id = :id") 910045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar E loadE(int id); 920045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 930045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Delete 940045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar void delete(A... a); 950045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 960045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Delete 970045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar void delete(B... b); 980045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 990045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Delete 1000045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar void delete(C... c); 1010045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 1020045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Query("UPDATE A SET name = :newName WHERE id = :id") 1030045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar void changeNameA(int id, String newName); 1040045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 1050045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Insert 1060045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar void insert(E... e); 1070045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 1080045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 1090045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 1100045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 1110045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Entity(indices = {@Index(value = "name", unique = true), 1120045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Index(value = {"name", "lastName"}, unique = true)}) 1130045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar static class A { 1140045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @PrimaryKey(autoGenerate = true) 1150045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public int id; 1160045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public String name; 1170045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public String lastName; 1180045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 1190045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar A(String name) { 1200045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar this.name = name; 1210045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 1220045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 123f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar @Ignore 1240045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar A(String name, String lastName) { 1250045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar this.name = name; 1260045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar this.lastName = lastName; 1270045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 1280045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 1290045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 1300045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @SuppressWarnings("WeakerAccess") 1310045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Entity(foreignKeys = { 1320045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @ForeignKey(entity = A.class, 1330045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar parentColumns = "name", 1340045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar childColumns = "aName")}) 1350045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 1360045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar static class B { 1370045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @PrimaryKey(autoGenerate = true) 1380045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public int id; 1390045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public String aName; 1400045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 1410045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar B(String aName) { 1420045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar this.aName = aName; 1430045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 1440045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 1450045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 1460045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @SuppressWarnings("WeakerAccess") 1470045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Entity(foreignKeys = { 1480045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @ForeignKey(entity = A.class, 1490045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar parentColumns = "name", 1500045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar childColumns = "aName", 1510045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar deferred = true)}) 1520045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar static class C { 1530045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @PrimaryKey(autoGenerate = true) 1540045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public int id; 1550045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public String aName; 1560045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 1570045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar C(String aName) { 1580045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar this.aName = aName; 1590045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 1600045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 1610045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 1620045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @SuppressWarnings("WeakerAccess") 1630045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Entity(foreignKeys = { 1640045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @ForeignKey(entity = A.class, 1650045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar parentColumns = "name", 1660045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar childColumns = "aName", 1670045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar onDelete = ForeignKey.CASCADE, 1680045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar onUpdate = ForeignKey.CASCADE)}) 1690045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar static class D { 1700045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @PrimaryKey(autoGenerate = true) 1710045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public int id; 1720045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public String aName; 1730045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 1740045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar D(String aName) { 1750045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar this.aName = aName; 1760045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 1770045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 1780045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 1790045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @SuppressWarnings("WeakerAccess") 1800045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Entity(foreignKeys = { 1810045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @ForeignKey(entity = A.class, 1820045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar parentColumns = {"name", "lastName"}, 1830045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar childColumns = {"aName", "aLastName"}, 1840045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar onDelete = ForeignKey.SET_NULL, 1850045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar onUpdate = ForeignKey.CASCADE)}) 1860045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar static class E { 1870045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @PrimaryKey(autoGenerate = true) 1880045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public int id; 1890045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public String aName; 1900045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public String aLastName; 1910045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 1920045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar E() { 1930045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 1940045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 195f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar @Ignore 1960045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar E(String aName, String aLastName) { 1970045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar this.aName = aName; 1980045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar this.aLastName = aLastName; 1990045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 2000045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 2010045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 2020045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 2030045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar private ForeignKeyDb mDb; 2040045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar private FkDao mDao; 2050045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 2060045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Before 2070045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public void openDb() { 2086be69eb5aa66706ff5880e12c17ea6e62c35eda3Yuichi Araki mDb = Room.inMemoryDatabaseBuilder(InstrumentationRegistry.getTargetContext(), 2090045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar ForeignKeyDb.class).build(); 2100045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao = mDb.dao(); 2110045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 2120045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 2130045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Test 2140045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public void simpleForeignKeyFailure() { 2150045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar Throwable t = catchException(new ThrowingRunnable() { 2160045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Override 2170045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public void run() throws Exception { 2180045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.insert(new B("foo")); 2190045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 2200045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar }); 2210045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar assertThat(t, instanceOf(SQLiteException.class)); 22224b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Araki assertThat(t.getMessage().toUpperCase(Locale.US), is(foreignKeyErrorMessage())); 2230045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 2240045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 2250045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Test 2260045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public void simpleForeignKeyDeferredFailure() { 2270045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar Throwable t = catchException(new ThrowingRunnable() { 2280045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Override 2290045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public void run() throws Exception { 2300045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.insert(new C("foo")); 2310045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 2320045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar }); 2330045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar assertThat(t, instanceOf(SQLiteException.class)); 23424b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Araki assertThat(t.getMessage().toUpperCase(Locale.US), is(foreignKeyErrorMessage())); 2350045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 2360045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 2370045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Test 2380045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public void immediateForeignKeyFailure() { 2390045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar Throwable t = catchException(new ThrowingRunnable() { 2400045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Override 2410045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public void run() throws Exception { 2420045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar try { 2430045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDb.beginTransaction(); 2440045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.insert(new B("foo")); 2450045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.insert(new A("foo")); 2460045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDb.setTransactionSuccessful(); 2470045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } finally { 2480045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDb.endTransaction(); 2490045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 2500045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 2510045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar }); 2520045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar assertThat(t, instanceOf(SQLiteException.class)); 2530045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 2540045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 2550045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Test 2560045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public void deferredForeignKeySuccess() { 2570045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar try { 2580045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDb.beginTransaction(); 2590045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.insert(new C("foo")); 2600045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.insert(new A("foo")); 2610045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDb.setTransactionSuccessful(); 2620045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } finally { 2630045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDb.endTransaction(); 2640045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 2650045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar assertThat(mDao.loadA(1), notNullValue()); 2660045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar assertThat(mDao.loadC(1), notNullValue()); 2670045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 2680045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 2690045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Test 2700045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public void onDelete_noAction() { 2710045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.insert(new A("a1")); 2720045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar final A a = mDao.loadA(1); 2730045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.insert(new B("a1")); 2740045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar Throwable t = catchException(new ThrowingRunnable() { 2750045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Override 2760045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public void run() throws Exception { 2770045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.delete(a); 2780045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 2790045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar }); 2800045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar assertThat(t, instanceOf(SQLiteException.class)); 28124b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Araki assertThat(t.getMessage().toUpperCase(Locale.US), is(foreignKeyErrorMessage())); 2820045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 2830045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 2840045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Test 2850045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public void onDelete_noAction_withTransaction() { 2860045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.insert(new A("a1")); 2870045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar final A a = mDao.loadA(1); 2880045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.insert(new B("a1")); 2890045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar final B b = mDao.loadB(1); 2900045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar Throwable t = catchException(new ThrowingRunnable() { 2910045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Override 2920045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public void run() throws Exception { 2930045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar deleteInTransaction(a, b); 2940045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 2950045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar }); 2960045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar assertThat(t, instanceOf(SQLiteException.class)); 29724b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Araki assertThat(t.getMessage().toUpperCase(Locale.US), is(foreignKeyErrorMessage())); 2980045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 2990045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 3000045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Test 3010045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public void onDelete_noAction_deferred() { 3020045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.insert(new A("a1")); 3030045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar final A a = mDao.loadA(1); 3040045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.insert(new C("a1")); 3050045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar Throwable t = catchException(new ThrowingRunnable() { 3060045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Override 3070045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public void run() throws Exception { 3080045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.delete(a); 3090045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 3100045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar }); 3110045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar assertThat(t, instanceOf(SQLiteException.class)); 31224b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Araki assertThat(t.getMessage().toUpperCase(Locale.US), is(foreignKeyErrorMessage())); 3130045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 3140045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 3150045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Test 3160045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public void onDelete_noAction__deferredWithTransaction() { 3170045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.insert(new A("a1")); 3180045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar final A a = mDao.loadA(1); 3190045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.insert(new C("a1")); 3200045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar final C c = mDao.loadC(1); 3210045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar deleteInTransaction(a, c); 3220045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 3230045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 3240045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Test 3250045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public void onDelete_cascade() { 3260045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.insert(new A("a1")); 3270045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar final A a = mDao.loadA(1); 3280045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.insert(new D("a1")); 3290045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar final D d = mDao.loadD(1); 3300045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar assertThat("test sanity", d, notNullValue()); 3310045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.delete(a); 3320045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar assertThat(mDao.loadD(1), nullValue()); 3330045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 3340045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 3350045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Test 3360045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public void onUpdate_cascade() { 3370045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.insert(new A("a1")); 3380045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.insert(new D("a1")); 3390045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar final D d = mDao.loadD(1); 3400045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar assertThat("test sanity", d, notNullValue()); 3410045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.changeNameA(1, "bla"); 3420045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar assertThat(mDao.loadD(1).aName, equalTo("bla")); 3430045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar assertThat(mDao.loadA(1).name, equalTo("bla")); 3440045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 3450045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 3460045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Test 3470045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public void multipleReferences() { 3480045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.insert(new A("a1", "a2")); 3490045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar final A a = mDao.loadA(1); 3500045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar assertThat("test sanity", a, notNullValue()); 3510045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar Throwable t = catchException(new ThrowingRunnable() { 3520045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Override 3530045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public void run() throws Exception { 3540045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.insert(new E("a1", "dsa")); 3550045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 3560045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar }); 35724b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Araki assertThat(t.getMessage().toUpperCase(Locale.US), is(foreignKeyErrorMessage())); 3580045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 3590045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 3600045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Test 3610045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public void onDelete_setNull_multipleReferences() { 3620045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.insert(new A("a1", "a2")); 3630045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar final A a = mDao.loadA(1); 3640045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.insert(new E("a1", "a2")); 3650045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar assertThat(mDao.loadE(1), notNullValue()); 3660045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.delete(a); 3670045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar E e = mDao.loadE(1); 3680045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar assertThat(e, notNullValue()); 3690045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar assertThat(e.aName, nullValue()); 3700045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar assertThat(e.aLastName, nullValue()); 3710045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 3720045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 3730045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @Test 3740045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar public void onUpdate_cascade_multipleReferences() { 3750045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.insert(new A("a1", "a2")); 3760045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar final A a = mDao.loadA(1); 3770045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.insert(new E("a1", "a2")); 3780045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar assertThat(mDao.loadE(1), notNullValue()); 3790045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.changeNameA(1, "foo"); 3800045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar assertThat(mDao.loadE(1), notNullValue()); 3810045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar assertThat(mDao.loadE(1).aName, equalTo("foo")); 3820045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar assertThat(mDao.loadE(1).aLastName, equalTo("a2")); 3830045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 3840045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 38524b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Araki private static Matcher<String> foreignKeyErrorMessage() { 38624b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Araki return either(containsString("FOREIGN KEY")) 38724b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Araki .or(both(containsString("CODE 19")).and(containsString("CONSTRAINT FAILED"))); 38824b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Araki } 38924b0c2d5bde2848da5caa57d9b1ec2a95d12bcd9Yuichi Araki 3900045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @SuppressWarnings("Duplicates") 3910045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar private void deleteInTransaction(A a, B b) { 3920045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDb.beginTransaction(); 3930045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar try { 3940045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.delete(a); 3950045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.delete(b); 3960045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDb.setTransactionSuccessful(); 3970045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } finally { 3980045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDb.endTransaction(); 3990045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 4000045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 4010045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 4020045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar @SuppressWarnings("Duplicates") 4030045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar private void deleteInTransaction(A a, C c) { 4040045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDb.beginTransaction(); 4050045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar try { 4060045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.delete(a); 4070045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDao.delete(c); 4080045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDb.setTransactionSuccessful(); 4090045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } finally { 4100045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar mDb.endTransaction(); 4110045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 4120045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 4130045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 4140045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar private static Throwable catchException(ThrowingRunnable throwingRunnable) { 4150045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar try { 4160045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar throwingRunnable.run(); 4170045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } catch (Throwable t) { 4180045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar return t; 4190045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 4200045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar throw new RuntimeException("didn't throw an exception"); 4210045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 4220045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar 4230045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar private interface ThrowingRunnable { 4240045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar void run() throws Exception; 4250045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar } 4260045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar} 427