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 */
16package androidx.room;
17
18import static org.hamcrest.CoreMatchers.is;
19import static org.hamcrest.CoreMatchers.not;
20import static org.hamcrest.CoreMatchers.notNullValue;
21import static org.hamcrest.MatcherAssert.assertThat;
22import static org.mockito.Matchers.anyString;
23import static org.mockito.Mockito.mock;
24import static org.mockito.Mockito.verify;
25import static org.mockito.Mockito.when;
26
27import androidx.sqlite.db.SupportSQLiteStatement;
28
29import org.junit.Before;
30import org.junit.Test;
31import org.junit.runner.RunWith;
32import org.junit.runners.JUnit4;
33import org.mockito.invocation.InvocationOnMock;
34import org.mockito.stubbing.Answer;
35
36import java.util.concurrent.Callable;
37import java.util.concurrent.ExecutionException;
38import java.util.concurrent.FutureTask;
39
40@RunWith(JUnit4.class)
41public class SharedSQLiteStatementTest {
42    private SharedSQLiteStatement mSharedStmt;
43    RoomDatabase mDb;
44    @Before
45    public void init() {
46        mDb = mock(RoomDatabase.class);
47        when(mDb.compileStatement(anyString())).thenAnswer(new Answer<SupportSQLiteStatement>() {
48
49            @Override
50            public SupportSQLiteStatement answer(InvocationOnMock invocation) throws Throwable {
51                return mock(SupportSQLiteStatement.class);
52            }
53        });
54        when(mDb.getInvalidationTracker()).thenReturn(mock(InvalidationTracker.class));
55        mSharedStmt = new SharedSQLiteStatement(mDb) {
56            @Override
57            protected String createQuery() {
58                return "foo";
59            }
60        };
61    }
62
63    @Test
64    public void checkMainThread() {
65        mSharedStmt.acquire();
66        verify(mDb).assertNotMainThread();
67    }
68
69    @Test
70    public void basic() {
71        assertThat(mSharedStmt.acquire(), notNullValue());
72    }
73
74    @Test
75    public void getTwiceWithoutReleasing() {
76        SupportSQLiteStatement stmt1 = mSharedStmt.acquire();
77        SupportSQLiteStatement stmt2 = mSharedStmt.acquire();
78        assertThat(stmt1, notNullValue());
79        assertThat(stmt2, notNullValue());
80        assertThat(stmt1, is(not(stmt2)));
81    }
82
83    @Test
84    public void getTwiceWithReleasing() {
85        SupportSQLiteStatement stmt1 = mSharedStmt.acquire();
86        mSharedStmt.release(stmt1);
87        SupportSQLiteStatement stmt2 = mSharedStmt.acquire();
88        assertThat(stmt1, notNullValue());
89        assertThat(stmt1, is(stmt2));
90    }
91
92    @Test
93    public void getFromAnotherThreadWhileHolding() throws ExecutionException, InterruptedException {
94        SupportSQLiteStatement stmt1 = mSharedStmt.acquire();
95        FutureTask<SupportSQLiteStatement> task = new FutureTask<>(
96                new Callable<SupportSQLiteStatement>() {
97                    @Override
98                    public SupportSQLiteStatement call() throws Exception {
99                        return mSharedStmt.acquire();
100                    }
101                });
102        new Thread(task).run();
103        SupportSQLiteStatement stmt2 = task.get();
104        assertThat(stmt1, notNullValue());
105        assertThat(stmt2, notNullValue());
106        assertThat(stmt1, is(not(stmt2)));
107    }
108
109    @Test
110    public void getFromAnotherThreadAfterReleasing() throws ExecutionException,
111            InterruptedException {
112        SupportSQLiteStatement stmt1 = mSharedStmt.acquire();
113        mSharedStmt.release(stmt1);
114        FutureTask<SupportSQLiteStatement> task = new FutureTask<>(
115                new Callable<SupportSQLiteStatement>() {
116                    @Override
117                    public SupportSQLiteStatement call() throws Exception {
118                        return mSharedStmt.acquire();
119                    }
120                });
121        new Thread(task).run();
122        SupportSQLiteStatement stmt2 = task.get();
123        assertThat(stmt1, notNullValue());
124        assertThat(stmt1, is(stmt2));
125    }
126}
127