SQLiteConnectionTests.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/Math/Uuid.h>
  9. #include <AzCore/std/smart_ptr/unique_ptr.h>
  10. #include <AzCore/std/string/string.h>
  11. #include <AzCore/IO/SystemFile.h>
  12. #include <AzCore/UnitTest/TestTypes.h>
  13. #include <AzToolsFramework/SQLite/SQLiteConnection.h>
  14. namespace UnitTest
  15. {
  16. using namespace AzToolsFramework;
  17. static int s_numTablesToCreate = 100;
  18. // we'll do about as much as we can get away with for about a second with most modern CPU
  19. static int s_numTrialsToPerform = 10500;
  20. class SQLiteTest
  21. : public LeakDetectionFixture
  22. {
  23. public:
  24. SQLiteTest()
  25. : LeakDetectionFixture()
  26. {
  27. }
  28. ~SQLiteTest() override = default;
  29. void SetUp() override
  30. {
  31. LeakDetectionFixture::SetUp();
  32. m_database.reset(aznew SQLite::Connection());
  33. m_randomDatabaseFileName = AZStd::string::format("%s_temp.sqlite", AZ::Uuid::CreateRandom().ToString<AZStd::string>().c_str());
  34. m_database->Open(m_randomDatabaseFileName.c_str(), false);
  35. }
  36. void TearDown() override
  37. {
  38. m_database->Close();
  39. m_database.reset();
  40. AZ::IO::SystemFile::Delete(m_randomDatabaseFileName.c_str());
  41. m_randomDatabaseFileName.set_capacity(0);
  42. LeakDetectionFixture::TearDown();
  43. }
  44. AZStd::string m_randomDatabaseFileName;
  45. AZStd::unique_ptr<SQLite::Connection> m_database;
  46. };
  47. TEST_F(SQLiteTest, DoesTableExist_BadInputs_ShouldAssert)
  48. {
  49. ASSERT_TRUE(m_database->IsOpen());
  50. // basic tests, bad input:
  51. AZ_TEST_START_TRACE_SUPPRESSION;
  52. EXPECT_FALSE(m_database->DoesTableExist(""));
  53. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  54. AZ_TEST_START_TRACE_SUPPRESSION;
  55. EXPECT_FALSE(m_database->DoesTableExist(nullptr));
  56. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  57. }
  58. // DoesTableExist had an off-by-one error in its string. It would not always crash.
  59. // This just stress tests that function (which also tests statement creation and destruction) to ensure
  60. // that if there is a problem with failing creation of functions, we don't crash.
  61. TEST_F(SQLiteTest, DoesTableExist_BasicFuzzTest_BadTableNames_ShouldNotAssert_ShouldReturnFalse)
  62. {
  63. ASSERT_TRUE(m_database->IsOpen());
  64. // now make up some random table names and try them out - none should exist.
  65. AZStd::string randomJunkTableName;
  66. randomJunkTableName.resize(16, '\0');
  67. for (int trialNumber = 0; trialNumber < s_numTrialsToPerform; ++trialNumber)
  68. {
  69. for (int randomChar = 0; randomChar < 16; ++randomChar)
  70. {
  71. // note that this also puts characters AFTER the null, if a null appears in the mddle.
  72. // so that if there are off by one errors they could include cruft afterwards.
  73. randomJunkTableName[randomChar] = (char)(rand() % 256); // this will trigger invalid UTF8 decoding too
  74. }
  75. randomJunkTableName[0] = 'a'; // just to make sure we don't retry the null case.
  76. EXPECT_FALSE(m_database->DoesTableExist(randomJunkTableName.c_str()));
  77. }
  78. }
  79. // this makes sure that repeated calls to DoesTableExist does not cause some crazy assertion or failure
  80. // if code is incorrect, it might, because DoesTableExists tends to create and destroy temporary statments.
  81. // as a coincidence, this also serves as somewhat of a stress test for all the other parts of the database
  82. // since this tests both creation of statements, execution of them, and retiring / cleaning the memory / freeing them
  83. TEST_F(SQLiteTest, DoesTableExist_BasicStressTest_GoodTableNames_ShouldNotAssert_ShouldReturnTrue)
  84. {
  85. // --- SETUP PHASE ----
  86. ASSERT_TRUE(m_database->IsOpen());
  87. // outside scope to improve reuse memory performance.
  88. AZStd::string randomValidTableName;
  89. AZStd::string createDatabaseTableStatement;
  90. for (int tableToCreate = 0; tableToCreate < s_numTablesToCreate; ++tableToCreate)
  91. {
  92. randomValidTableName = AZStd::string::format("testtable_%i", tableToCreate);
  93. createDatabaseTableStatement = AZStd::string::format(
  94. "CREATE TABLE IF NOT EXISTS %s( "
  95. " rowID INTEGER PRIMARY KEY, "
  96. " version INTEGER NOT NULL);", randomValidTableName.c_str());
  97. m_database->AddStatement(randomValidTableName, createDatabaseTableStatement);
  98. EXPECT_TRUE(m_database->ExecuteOneOffStatement(randomValidTableName.c_str()));
  99. m_database->RemoveStatement(randomValidTableName.c_str());
  100. }
  101. // --- TEST PHASE ----
  102. for (int trialNumber = 0; trialNumber < s_numTrialsToPerform; ++trialNumber)
  103. {
  104. randomValidTableName = AZStd::string::format("testtable_%i", rand() % s_numTablesToCreate);
  105. EXPECT_TRUE(m_database->DoesTableExist(randomValidTableName.c_str()));
  106. }
  107. }
  108. }