1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <string>
6
7#include "base/bind.h"
8#include "base/files/file_util.h"
9#include "base/files/scoped_temp_dir.h"
10#include "sql/connection.h"
11#include "sql/statement.h"
12#include "sql/test/error_callback_support.h"
13#include "sql/test/scoped_error_ignorer.h"
14#include "testing/gtest/include/gtest/gtest.h"
15#include "third_party/sqlite/sqlite3.h"
16
17namespace {
18
19class SQLStatementTest : public testing::Test {
20 public:
21  virtual void SetUp() {
22    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
23    ASSERT_TRUE(db_.Open(temp_dir_.path().AppendASCII("SQLStatementTest.db")));
24  }
25
26  virtual void TearDown() {
27    db_.Close();
28  }
29
30  sql::Connection& db() { return db_; }
31
32 private:
33  base::ScopedTempDir temp_dir_;
34  sql::Connection db_;
35};
36
37}  // namespace
38
39TEST_F(SQLStatementTest, Assign) {
40  sql::Statement s;
41  EXPECT_FALSE(s.is_valid());
42
43  s.Assign(db().GetUniqueStatement("CREATE TABLE foo (a, b)"));
44  EXPECT_TRUE(s.is_valid());
45}
46
47TEST_F(SQLStatementTest, Run) {
48  ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
49  ASSERT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (3, 12)"));
50
51  sql::Statement s(db().GetUniqueStatement("SELECT b FROM foo WHERE a=?"));
52  EXPECT_FALSE(s.Succeeded());
53
54  // Stepping it won't work since we haven't bound the value.
55  EXPECT_FALSE(s.Step());
56
57  // Run should fail since this produces output, and we should use Step(). This
58  // gets a bit wonky since sqlite says this is OK so succeeded is set.
59  s.Reset(true);
60  s.BindInt(0, 3);
61  EXPECT_FALSE(s.Run());
62  EXPECT_EQ(SQLITE_ROW, db().GetErrorCode());
63  EXPECT_TRUE(s.Succeeded());
64
65  // Resetting it should put it back to the previous state (not runnable).
66  s.Reset(true);
67  EXPECT_FALSE(s.Succeeded());
68
69  // Binding and stepping should produce one row.
70  s.BindInt(0, 3);
71  EXPECT_TRUE(s.Step());
72  EXPECT_TRUE(s.Succeeded());
73  EXPECT_EQ(12, s.ColumnInt(0));
74  EXPECT_FALSE(s.Step());
75  EXPECT_TRUE(s.Succeeded());
76}
77
78// Error callback called for error running a statement.
79TEST_F(SQLStatementTest, ErrorCallback) {
80  ASSERT_TRUE(db().Execute("CREATE TABLE foo (a INTEGER PRIMARY KEY, b)"));
81
82  int error = SQLITE_OK;
83  sql::ScopedErrorCallback sec(
84      &db(), base::Bind(&sql::CaptureErrorCallback, &error));
85
86  // Insert in the foo table the primary key. It is an error to insert
87  // something other than an number. This error causes the error callback
88  // handler to be called with SQLITE_MISMATCH as error code.
89  sql::Statement s(db().GetUniqueStatement("INSERT INTO foo (a) VALUES (?)"));
90  EXPECT_TRUE(s.is_valid());
91  s.BindCString(0, "bad bad");
92  EXPECT_FALSE(s.Run());
93  EXPECT_EQ(SQLITE_MISMATCH, error);
94}
95
96// Error ignorer works for error running a statement.
97TEST_F(SQLStatementTest, ScopedIgnoreError) {
98  ASSERT_TRUE(db().Execute("CREATE TABLE foo (a INTEGER PRIMARY KEY, b)"));
99
100  sql::Statement s(db().GetUniqueStatement("INSERT INTO foo (a) VALUES (?)"));
101  EXPECT_TRUE(s.is_valid());
102
103  sql::ScopedErrorIgnorer ignore_errors;
104  ignore_errors.IgnoreError(SQLITE_MISMATCH);
105  s.BindCString(0, "bad bad");
106  ASSERT_FALSE(s.Run());
107  ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
108}
109
110TEST_F(SQLStatementTest, Reset) {
111  ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
112  ASSERT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (3, 12)"));
113  ASSERT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (4, 13)"));
114
115  sql::Statement s(db().GetUniqueStatement(
116      "SELECT b FROM foo WHERE a = ? "));
117  s.BindInt(0, 3);
118  ASSERT_TRUE(s.Step());
119  EXPECT_EQ(12, s.ColumnInt(0));
120  ASSERT_FALSE(s.Step());
121
122  s.Reset(false);
123  // Verify that we can get all rows again.
124  ASSERT_TRUE(s.Step());
125  EXPECT_EQ(12, s.ColumnInt(0));
126  EXPECT_FALSE(s.Step());
127
128  s.Reset(true);
129  ASSERT_FALSE(s.Step());
130}
131