/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #include #include #include #include #include #include namespace UnitTest { using namespace AzToolsFramework; static int s_numTablesToCreate = 100; // we'll do about as much as we can get away with for about a second with most modern CPU static int s_numTrialsToPerform = 10500; class SQLiteTest : public AllocatorsFixture { public: SQLiteTest() : AllocatorsFixture() { } ~SQLiteTest() = default; void SetUp() override { AllocatorsFixture::SetUp(); m_database.reset(aznew SQLite::Connection()); m_randomDatabaseFileName = AZStd::string::format("%s_temp.sqlite", AZ::Uuid::CreateRandom().ToString().c_str()); m_database->Open(m_randomDatabaseFileName.c_str(), false); } void TearDown() override { m_database->Close(); m_database.reset(); AZ::IO::SystemFile::Delete(m_randomDatabaseFileName.c_str()); m_randomDatabaseFileName.set_capacity(0); AllocatorsFixture::TearDown(); } AZStd::string m_randomDatabaseFileName; AZStd::unique_ptr m_database; }; TEST_F(SQLiteTest, DoesTableExist_BadInputs_ShouldAssert) { ASSERT_TRUE(m_database->IsOpen()); // basic tests, bad input: AZ_TEST_START_TRACE_SUPPRESSION; EXPECT_FALSE(m_database->DoesTableExist("")); AZ_TEST_STOP_TRACE_SUPPRESSION(1); AZ_TEST_START_TRACE_SUPPRESSION; EXPECT_FALSE(m_database->DoesTableExist(nullptr)); AZ_TEST_STOP_TRACE_SUPPRESSION(1); } // DoesTableExist had an off-by-one error in its string. It would not always crash. // This just stress tests that function (which also tests statement creation and destruction) to ensure // that if there is a problem with failing creation of functions, we don't crash. TEST_F(SQLiteTest, DoesTableExist_BasicFuzzTest_BadTableNames_ShouldNotAssert_ShouldReturnFalse) { ASSERT_TRUE(m_database->IsOpen()); // now make up some random table names and try them out - none should exist. AZStd::string randomJunkTableName; randomJunkTableName.resize(16, '\0'); for (int trialNumber = 0; trialNumber < s_numTrialsToPerform; ++trialNumber) { for (int randomChar = 0; randomChar < 16; ++randomChar) { // note that this also puts characters AFTER the null, if a null appears in the mddle. // so that if there are off by one errors they could include cruft afterwards. randomJunkTableName[randomChar] = (char)(rand() % 256); // this will trigger invalid UTF8 decoding too } randomJunkTableName[0] = 'a'; // just to make sure we don't retry the null case. EXPECT_FALSE(m_database->DoesTableExist(randomJunkTableName.c_str())); } } // this makes sure that repeated calls to DoesTableExist does not cause some crazy assertion or failure // if code is incorrect, it might, because DoesTableExists tends to create and destroy temporary statments. // as a coincidence, this also serves as somewhat of a stress test for all the other parts of the database // since this tests both creation of statements, execution of them, and retiring / cleaning the memory / freeing them TEST_F(SQLiteTest, DoesTableExist_BasicStressTest_GoodTableNames_ShouldNotAssert_ShouldReturnTrue) { // --- SETUP PHASE ---- ASSERT_TRUE(m_database->IsOpen()); // outside scope to improve reuse memory performance. AZStd::string randomValidTableName; AZStd::string createDatabaseTableStatement; for (int tableToCreate = 0; tableToCreate < s_numTablesToCreate; ++tableToCreate) { randomValidTableName = AZStd::string::format("testtable_%i", tableToCreate); createDatabaseTableStatement = AZStd::string::format( "CREATE TABLE IF NOT EXISTS %s( " " rowID INTEGER PRIMARY KEY, " " version INTEGER NOT NULL);", randomValidTableName.c_str()); m_database->AddStatement(randomValidTableName, createDatabaseTableStatement); EXPECT_TRUE(m_database->ExecuteOneOffStatement(randomValidTableName.c_str())); m_database->RemoveStatement(randomValidTableName.c_str()); } // --- TEST PHASE ---- for (int trialNumber = 0; trialNumber < s_numTrialsToPerform; ++trialNumber) { randomValidTableName = AZStd::string::format("testtable_%i", rand() % s_numTablesToCreate); EXPECT_TRUE(m_database->DoesTableExist(randomValidTableName.c_str())); } } }