add catch2 based test setup including some basic test cases

This commit is contained in:
mlangkabel
2018-12-10 20:26:32 +01:00
parent a69232afed
commit 4d5b97b7e6
19 changed files with 15389 additions and 126 deletions
+28 -4
View File
@@ -2,6 +2,7 @@ cmake_minimum_required (VERSION 2.6)
set(PROJECT_NAME "SourcetrailDBCore")
set(LIB_NAME "sourcetraildb")
set(TEST_NAME "test")
set(INTERFACE_VERSION 0)
set(DATABASE_VERSION 22)
@@ -41,7 +42,7 @@ configure_file(
${GENERATED_VERSION_FILE}
)
set(SRC_FILES
set(LIB_SRC_FILES
external/sqlite/CppSQLite3.cpp
external/sqlite/sqlite3.c
src/DatabaseStorage.cpp
@@ -56,7 +57,7 @@ set(SRC_FILES
src/utility.cpp
)
set(HDR_FILES
set(LIB_HDR_FILES
external/json/json.hpp
external/sqlite/CppSQLite3.h
external/sqlite/sqlite3.h
@@ -70,17 +71,40 @@ set(HDR_FILES
include/ReferenceKind.h
include/SourceLocation.h
include/SourceRange.h
include/SourcetrailException.h
include/SourcetrailDBWriter.h
include/SourcetrailException.h
include/StorageEdge.h
include/StorageError.h
include/StorageFile.h
include/StorageLocalSymbol.h
include/StorageNode.h
include/StorageOccurrence.h
include/StorageSourceLocation.h
include/StorageSymbol.h
include/SymbolKind.h
include/utility.h
${GENERATED_VERSION_FILE}
)
add_library(${LIB_NAME} STATIC ${SRC_FILES} ${HDR_FILES})
add_library(${LIB_NAME} STATIC ${LIB_SRC_FILES} ${LIB_HDR_FILES})
target_include_directories(${LIB_NAME} PUBLIC
"${CMAKE_SOURCE_DIR}/include"
"${CMAKE_SOURCE_DIR}/external"
"${GENERATED_INCLUDE_DIRECTORY}"
)
set(TEST_SRC_FILES
test/test.cpp
)
add_executable(${TEST_NAME} ${TEST_SRC_FILES})
target_include_directories(${TEST_NAME} PUBLIC
"${CMAKE_SOURCE_DIR}/include"
"${CMAKE_SOURCE_DIR}/external"
"${GENERATED_INCLUDE_DIRECTORY}"
)
target_link_libraries(${TEST_NAME} ${LIB_NAME})
+14361
View File
File diff suppressed because it is too large Load Diff
+43 -16
View File
@@ -19,9 +19,19 @@
#include <memory>
#include <string>
#include <vector>
#include "sqlite/CppSQLite3.h"
#include "StorageEdge.h"
#include "StorageError.h"
#include "StorageFile.h"
#include "StorageLocalSymbol.h"
#include "StorageNode.h"
#include "StorageOccurrence.h"
#include "StorageSourceLocation.h"
#include "StorageSymbol.h"
namespace sourcetrail
{
/**
@@ -49,25 +59,23 @@ namespace sourcetrail
void rollbackTransaction();
void optimizeDatabaseMemory();
int addNode(const std::string& serializedNameHierarchy);
void addSymbol(int symbolId, int definitionKind);
void addFile(int nodeId, const std::string& filePath);
int addEdge(int sourceId, int targetId, int edgeKind);
int addLocalSymbol(const std::string& name);
int addSourceLocation(
int fileId,
int startLineNumber,
int startColumnNumber,
int endLineNumber,
int endColumnNumber,
int locationKind);
void addOccurrence(int elementId, int sourceLocationId);
int addError(
const std::string& message,
bool fatal);
int addNode(const StorageNodeData& storageNodeData);
void addSymbol(const StorageSymbol& storageSymbol);
void addFile(const StorageFile& storageFile);
int addEdge(const StorageEdgeData& storageEdgeData);
int addLocalSymbol(const StorageLocalSymbolData& storageLocalSymbolData);
int addSourceLocation(const StorageSourceLocationData& storageSourceLocationData);
void addOccurrence(const StorageOccurrence& storageOccurrence);
int addError(const StorageErrorData& storageErrorData);
void setNodeType(int nodeId, int nodeKind);
template <typename ResultType>
std::vector<ResultType> getAll() const
{
return doGetAll<ResultType>("");
}
private:
DatabaseStorage() = default;
@@ -77,9 +85,28 @@ namespace sourcetrail
CppSQLite3Query executeQuery(const std::string& query) const;
CppSQLite3Query executeQuery(CppSQLite3Statement& statement) const;
template <typename ResultType>
std::vector<ResultType> doGetAll(const std::string& query) const;
mutable CppSQLite3DB m_database;
};
template <>
std::vector<StorageEdge> DatabaseStorage::doGetAll<StorageEdge>(const std::string& query) const;
template <>
std::vector<StorageNode> DatabaseStorage::doGetAll<StorageNode>(const std::string& query) const;
template <>
std::vector<StorageSymbol> DatabaseStorage::doGetAll<StorageSymbol>(const std::string& query) const;
template <>
std::vector<StorageFile> DatabaseStorage::doGetAll<StorageFile>(const std::string& query) const;
template <>
std::vector<StorageLocalSymbol> DatabaseStorage::doGetAll<StorageLocalSymbol>(const std::string& query) const;
template <>
std::vector<StorageSourceLocation> DatabaseStorage::doGetAll<StorageSourceLocation>(const std::string& query) const;
template <>
std::vector<StorageOccurrence> DatabaseStorage::doGetAll<StorageOccurrence>(const std::string& query) const;
template <>
std::vector<StorageError> DatabaseStorage::doGetAll<StorageError>(const std::string& query) const;
}
#endif // SOURCETRAIL_DATABASE_STORAGE_H
+9 -12
View File
@@ -20,18 +20,17 @@
#include <memory>
#include <string>
#include "DefinitionKind.h"
#include "EdgeKind.h"
#include "LocationKind.h"
#include "NameHierarchy.h"
#include "ReferenceKind.h"
#include "SourceRange.h"
#include "SymbolKind.h"
namespace sourcetrail
{
class DatabaseStorage;
struct SourceRange;
struct NameHierarchy;
enum DefinitionKind;
enum EdgeKind;
enum LocationKind;
enum ReferenceKind;
enum SymbolKind;
class DatabaseStorage; // forward declaration prevents leakage of sqlite include dependency to users of the SourcetrailDBWriter
/**
* Class wrapping the main interface for writing data to a Sourcetrail project database.
@@ -89,8 +88,6 @@ namespace sourcetrail
private:
static std::string serializeNameHierarchy(const NameHierarchy& nameHierarchy);
std::string getProjectFilePath() const;
std::string getDatabaseFilePath() const;
void openDatabase();
void closeDatabase();
void setupDatabaseTables();
+62
View File
@@ -0,0 +1,62 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_STORAGE_EDGE_H
#define SOURCETRAIL_STORAGE_EDGE_H
namespace sourcetrail
{
struct StorageEdgeData
{
StorageEdgeData()
: sourceNodeId(0)
, targetNodeId(0)
, edgeKind(0)
{}
StorageEdgeData(int sourceNodeId, int targetNodeId, int edgeKind)
: sourceNodeId(sourceNodeId)
, targetNodeId(targetNodeId)
, edgeKind(edgeKind)
{}
int sourceNodeId;
int targetNodeId;
int edgeKind;
};
struct StorageEdge : public StorageEdgeData
{
StorageEdge()
: StorageEdgeData()
, id(0)
{}
StorageEdge(int id, const StorageEdgeData& data)
: StorageEdgeData(data)
, id(id)
{}
StorageEdge(int id, int sourceNodeId, int targetNodeId, int edgeKind)
: StorageEdgeData(sourceNodeId, targetNodeId, edgeKind)
, id(id)
{}
int id;
};
}
#endif // SOURCETRAIL_STORAGE_EDGE_H
+84
View File
@@ -0,0 +1,84 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_STORAGE_ERROR_H
#define SOURCETRAIL_STORAGE_ERROR_H
#include <string>
namespace sourcetrail
{
struct StorageErrorData
{
StorageErrorData()
: message("")
, translationUnit("")
, fatal(0)
, indexed(0)
{}
StorageErrorData(
std::string message,
std::string translationUnit,
bool fatal,
bool indexed
)
: message(std::move(message))
, translationUnit(std::move(translationUnit))
, fatal(fatal)
, indexed(indexed)
{}
std::string message;
std::string translationUnit;
bool fatal;
bool indexed;
};
struct StorageError : public StorageErrorData
{
StorageError()
: StorageErrorData()
, id(0)
{}
StorageError(int id, const StorageErrorData& data)
: StorageErrorData(data)
, id(id)
{}
StorageError(
int id,
std::string message,
std::string translationUnit,
bool fatal,
bool indexed
)
: StorageErrorData(
std::move(message),
std::move(translationUnit),
fatal,
indexed
)
, id(id)
{}
int id;
};
}
#endif // SOURCETRAIL_STORAGE_ERROR_H
+58
View File
@@ -0,0 +1,58 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_STORAGE_FILE_H
#define SOURCETRAIL_STORAGE_FILE_H
#include <string>
namespace sourcetrail
{
struct StorageFile
{
StorageFile()
: id(0)
, filePath("")
, modificationTime("")
, indexed(true)
, complete(true)
{}
StorageFile(int id, std::string filePath, bool indexed, bool complete)
: id(id)
, filePath(std::move(filePath))
, modificationTime("")
, indexed(indexed)
, complete(complete)
{}
StorageFile(int id, std::string filePath, std::string modificationTime, bool indexed, bool complete)
: id(id)
, filePath(std::move(filePath))
, modificationTime(std::move(modificationTime))
, indexed(indexed)
, complete(complete)
{}
int id;
std::string filePath;
std::string modificationTime;
bool indexed;
bool complete;
};
}
#endif // SOURCETRAIL_STORAGE_FILE_H
+58
View File
@@ -0,0 +1,58 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_STORAGE_LOCAL_SYMBOL_H
#define SOURCETRAIL_STORAGE_LOCAL_SYMBOL_H
#include <string>
namespace sourcetrail
{
struct StorageLocalSymbolData
{
StorageLocalSymbolData()
: name("")
{}
StorageLocalSymbolData(std::string name)
: name(std::move(name))
{}
std::string name;
};
struct StorageLocalSymbol : public StorageLocalSymbolData
{
StorageLocalSymbol()
: StorageLocalSymbolData()
, id(0)
{}
StorageLocalSymbol(int id, const StorageLocalSymbolData& data)
: StorageLocalSymbolData(data)
, id(id)
{}
StorageLocalSymbol(int id, std::string name)
: StorageLocalSymbolData(std::move(name))
, id(id)
{}
int id;
};
}
#endif // SOURCETRAIL_STORAGE_LOCAL_SYMBOL_H
+61
View File
@@ -0,0 +1,61 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_STORAGE_NODE_H
#define SOURCETRAIL_STORAGE_NODE_H
#include <string>
namespace sourcetrail
{
struct StorageNodeData
{
StorageNodeData()
: nodeKind(0)
, serializedName("")
{}
StorageNodeData(int nodeKind, std::string serializedName)
: nodeKind(nodeKind)
, serializedName(std::move(serializedName))
{}
int nodeKind;
std::string serializedName;
};
struct StorageNode : public StorageNodeData
{
StorageNode()
: StorageNodeData()
, id(0)
{}
StorageNode(int id, int nodeKind, std::string serializedName)
: StorageNodeData(nodeKind, std::move(serializedName))
, id(id)
{}
StorageNode(int id, const StorageNodeData& data)
: StorageNodeData(data)
, id(id)
{}
int id;
};
}
#endif // SOURCETRAIL_STORAGE_NODE_H
+39
View File
@@ -0,0 +1,39 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_STORAGE_OCCURRENCE_H
#define SOURCETRAIL_STORAGE_OCCURRENCE_H
namespace sourcetrail
{
struct StorageOccurrence
{
StorageOccurrence()
: elementId(0)
, sourceLocationId(0)
{}
StorageOccurrence(int elementId, int sourceLocationId)
: elementId(elementId)
, sourceLocationId(sourceLocationId)
{}
int elementId;
int sourceLocationId;
};
}
#endif // SOURCETRAIL_STORAGE_OCCURRENCE_H
+71
View File
@@ -0,0 +1,71 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_STORAGE_SOURCE_LOCATION_H
#define SOURCETRAIL_STORAGE_SOURCE_LOCATION_H
namespace sourcetrail
{
struct StorageSourceLocationData
{
StorageSourceLocationData()
: fileNodeId(0)
, startLineNumber(-1)
, startColumnNumber(-1)
, endLineNumber(-1)
, endColumnNumber(-1)
, locationKind(0)
{}
StorageSourceLocationData(int fileNodeId, int startLineNumber, int startColumnNumber, int endLineNumber, int endColumnNumber, int locationKind)
: fileNodeId(fileNodeId)
, startLineNumber(startLineNumber)
, startColumnNumber(startColumnNumber)
, endLineNumber(endLineNumber)
, endColumnNumber(endColumnNumber)
, locationKind(locationKind)
{}
int fileNodeId;
int startLineNumber;
int startColumnNumber;
int endLineNumber;
int endColumnNumber;
int locationKind;
};
struct StorageSourceLocation : public StorageSourceLocationData
{
StorageSourceLocation()
: StorageSourceLocationData()
, id(0)
{}
StorageSourceLocation(int id, const StorageSourceLocationData& data)
: StorageSourceLocationData(data)
, id(id)
{}
StorageSourceLocation(int id, int fileNodeId, int startLineNumber, int startColumnNumber, int endLineNumber, int endColumnNumber, int locationKind)
: StorageSourceLocationData(fileNodeId, startLineNumber, startColumnNumber, endLineNumber, endColumnNumber, locationKind)
, id(id)
{}
int id;
};
}
#endif // SOURCETRAIL_STORAGE_SOURCE_LOCATION_H
+41
View File
@@ -0,0 +1,41 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_STORAGE_SYMBOL_H
#define SOURCETRAIL_STORAGE_SYMBOL_H
#include "DefinitionKind.h"
namespace sourcetrail
{
struct StorageSymbol
{
StorageSymbol()
: id(0)
, definitionKind(definitionKindToInt(DEFINITION_EXPLICIT))
{}
StorageSymbol(int id, int definitionKind)
: id(id)
, definitionKind(definitionKind)
{}
int id;
int definitionKind;
};
}
#endif // SOURCETRAIL_STORAGE_SYMBOL_H
-1
View File
@@ -26,7 +26,6 @@ namespace sourcetrail
{
bool getFileExists(const std::string& filePath);
std::string getFileContent(const std::string& filePath);
time_t getFileModificationTime(const std::string& filePath);
std::string getDateTimeString(const time_t& time);
int getLineCount(const std::string s);
}
+282 -67
View File
@@ -19,6 +19,9 @@
#include <vector>
#include "SourcetrailException.h"
#include "StorageFile.h"
#include "StorageNode.h"
#include "StorageSymbol.h"
#include "NodeKind.h"
#include "utility.h"
#include "version.h"
@@ -34,10 +37,17 @@ namespace sourcetrail
std::shared_ptr<DatabaseStorage> DatabaseStorage::openDatabase(const std::string& dbFilePath)
{
std::shared_ptr<DatabaseStorage> storage = std::shared_ptr<DatabaseStorage>(new DatabaseStorage());
storage->m_database.open(dbFilePath.c_str());
storage->executeStatement("PRAGMA foreign_keys=ON;");
return storage;
try
{
std::shared_ptr<DatabaseStorage> storage = std::shared_ptr<DatabaseStorage>(new DatabaseStorage());
storage->m_database.open(dbFilePath.c_str());
storage->executeStatement("PRAGMA foreign_keys=ON;");
return storage;
}
catch (CppSQLite3Exception e)
{
throw SourcetrailException(e.errorMessage());
}
}
DatabaseStorage::~DatabaseStorage()
@@ -269,7 +279,7 @@ namespace sourcetrail
executeStatement("VACUUM;");
}
int DatabaseStorage::addNode(const std::string& serializedNameHierarchy)
int DatabaseStorage::addNode(const StorageNodeData& storageNodeData)
{
int id = 0;
@@ -277,7 +287,7 @@ namespace sourcetrail
CppSQLite3Statement stmt = m_database.compileStatement(
"SELECT id FROM node WHERE serialized_name == ? LIMIT 1;"
);
stmt.bind(1, serializedNameHierarchy.c_str());
stmt.bind(1, storageNodeData.serializedName.c_str());
CppSQLite3Query q = executeQuery(stmt);
if (!q.eof())
{
@@ -285,6 +295,8 @@ namespace sourcetrail
}
}
// FIXME: update node nodeKind here
if (id == 0)
{
{
@@ -299,35 +311,42 @@ namespace sourcetrail
"INSERT INTO node(id, type, serialized_name) VALUES(?, ?, ?);"
);
stmt.bind(1, id);
stmt.bind(2, nodeKindToInt(NODE_UNKNOWN));
stmt.bind(3, serializedNameHierarchy.c_str());
stmt.bind(2, storageNodeData.nodeKind);
stmt.bind(3, storageNodeData.serializedName.c_str());
executeStatement(stmt);
}
}
return id;
}
void DatabaseStorage::addSymbol(int nodeId, int definitionKind)
void DatabaseStorage::addSymbol(const StorageSymbol& storageSymbol)
{
CppSQLite3Statement stmt = m_database.compileStatement(
"INSERT OR IGNORE INTO symbol(id, definition_kind) VALUES(?, ?);"
);
stmt.bind(1, nodeId);
stmt.bind(2, definitionKind);
stmt.bind(1, storageSymbol.id);
stmt.bind(2, storageSymbol.definitionKind);
executeStatement(stmt);
}
void DatabaseStorage::addFile(int nodeId, const std::string& filePath)
void DatabaseStorage::addFile(const StorageFile& storageFile)
{
std::string modificationTime = utility::getDateTimeString(0);
const bool indexed = true;
const bool complete = true;
std::string content = "";
if (utility::getFileExists(filePath))
{
modificationTime = utility::getDateTimeString(utility::getFileModificationTime(filePath));
content = utility::getFileContent(filePath);
CppSQLite3Statement stmt = m_database.compileStatement(
"SELECT id FROM file WHERE id == ?;"
);
stmt.bind(1, storageFile.id);
CppSQLite3Query q = executeQuery(stmt);
if (!q.eof())
{
return; // early exit if the file already exists
}
}
std::string content = "";
if (utility::getFileExists(storageFile.filePath))
{
content = utility::getFileContent(storageFile.filePath);
}
const int lineCount = utility::getLineCount(content);
@@ -335,11 +354,11 @@ namespace sourcetrail
CppSQLite3Statement stmt = m_database.compileStatement(
"INSERT OR IGNORE INTO file(id, path, modification_time, indexed, complete, line_count) VALUES(?, ?, ?, ?, ?, ?);"
);
stmt.bind(1, nodeId);
stmt.bind(2, filePath.c_str());
stmt.bind(3, modificationTime.c_str());
stmt.bind(4, indexed);
stmt.bind(5, complete);
stmt.bind(1, storageFile.id);
stmt.bind(2, storageFile.filePath.c_str());
stmt.bind(3, storageFile.modificationTime.c_str());
stmt.bind(4, storageFile.indexed);
stmt.bind(5, storageFile.complete);
stmt.bind(6, lineCount);
executeStatement(stmt);
}
@@ -349,13 +368,13 @@ namespace sourcetrail
CppSQLite3Statement stmt = m_database.compileStatement(
"INSERT INTO filecontent(id, content) VALUES(?, ?);"
);
stmt.bind(1, nodeId);
stmt.bind(1, storageFile.id);
stmt.bind(2, content.c_str());
executeStatement(stmt);
}
}
int DatabaseStorage::addEdge(int sourceNodeId, int targetNodeId, int edgeKind)
int DatabaseStorage::addEdge(const StorageEdgeData& storageEdgeData)
{
int id = 0;
@@ -363,9 +382,9 @@ namespace sourcetrail
CppSQLite3Statement stmt = m_database.compileStatement(
"SELECT id FROM edge WHERE source_node_id == ? AND target_node_id == ? AND type == ? LIMIT 1;"
);
stmt.bind(1, sourceNodeId);
stmt.bind(2, targetNodeId);
stmt.bind(3, edgeKind);
stmt.bind(1, storageEdgeData.sourceNodeId);
stmt.bind(2, storageEdgeData.targetNodeId);
stmt.bind(3, storageEdgeData.edgeKind);
CppSQLite3Query q = executeQuery(stmt);
if (!q.eof())
{
@@ -387,16 +406,16 @@ namespace sourcetrail
"INSERT INTO edge(id, type, source_node_id, target_node_id) VALUES(?, ?, ?, ?);"
);
stmt.bind(1, id);
stmt.bind(2, edgeKind);
stmt.bind(3, sourceNodeId);
stmt.bind(4, targetNodeId);
stmt.bind(2, storageEdgeData.edgeKind);
stmt.bind(3, storageEdgeData.sourceNodeId);
stmt.bind(4, storageEdgeData.targetNodeId);
executeStatement(stmt);
}
}
return id;
}
int DatabaseStorage::addLocalSymbol(const std::string& name)
int DatabaseStorage::addLocalSymbol(const StorageLocalSymbolData& storageLocalSymbolData)
{
int id = 0;
@@ -404,7 +423,7 @@ namespace sourcetrail
CppSQLite3Statement stmt = m_database.compileStatement(
"SELECT id FROM local_symbol WHERE name == ? LIMIT 1;"
);
stmt.bind(1, name.c_str());
stmt.bind(1, storageLocalSymbolData.name.c_str());
CppSQLite3Query q = executeQuery(stmt);
if (!q.eof())
{
@@ -426,20 +445,14 @@ namespace sourcetrail
"INSERT INTO local_symbol(id, name) VALUES(?, ?);"
);
stmt.bind(1, id);
stmt.bind(2, name.c_str());
stmt.bind(2, storageLocalSymbolData.name.c_str());
executeStatement(stmt);
}
}
return id;
}
int DatabaseStorage::addSourceLocation(
int fileId,
int startLineNumber,
int startColumnNumber,
int endLineNumber,
int endColumnNumber,
int locationKind)
int DatabaseStorage::addSourceLocation(const StorageSourceLocationData& storageSourceLocationData)
{
int id = 0;
@@ -454,12 +467,12 @@ namespace sourcetrail
"type = ? "
"LIMIT 1;"
);
stmt.bind(1, fileId);
stmt.bind(2, startLineNumber);
stmt.bind(3, startColumnNumber);
stmt.bind(4, endLineNumber);
stmt.bind(5, endColumnNumber);
stmt.bind(6, locationKind);
stmt.bind(1, storageSourceLocationData.fileNodeId);
stmt.bind(2, storageSourceLocationData.startLineNumber);
stmt.bind(3, storageSourceLocationData.startColumnNumber);
stmt.bind(4, storageSourceLocationData.endLineNumber);
stmt.bind(5, storageSourceLocationData.endColumnNumber);
stmt.bind(6, storageSourceLocationData.locationKind);
CppSQLite3Query q = executeQuery(stmt);
if (!q.eof())
{
@@ -472,31 +485,29 @@ namespace sourcetrail
CppSQLite3Statement stmt = m_database.compileStatement(
"INSERT INTO source_location(id, file_node_id, start_line, start_column, end_line, end_column, type) VALUES(NULL, ?, ?, ?, ?, ?, ?);"
);
stmt.bind(1, fileId);
stmt.bind(2, startLineNumber);
stmt.bind(3, startColumnNumber);
stmt.bind(4, endLineNumber);
stmt.bind(5, endColumnNumber);
stmt.bind(6, locationKind);
stmt.bind(1, storageSourceLocationData.fileNodeId);
stmt.bind(2, storageSourceLocationData.startLineNumber);
stmt.bind(3, storageSourceLocationData.startColumnNumber);
stmt.bind(4, storageSourceLocationData.endLineNumber);
stmt.bind(5, storageSourceLocationData.endColumnNumber);
stmt.bind(6, storageSourceLocationData.locationKind);
executeStatement(stmt);
id = m_database.lastRowId();
}
return id;
}
void DatabaseStorage::addOccurrence(int elementId, int sourceLocationId)
void DatabaseStorage::addOccurrence(const StorageOccurrence& storageOccurrence)
{
CppSQLite3Statement stmt = m_database.compileStatement(
"INSERT OR IGNORE INTO occurrence(element_id, source_location_id) VALUES(?, ?);"
);
stmt.bind(1, elementId);
stmt.bind(2, sourceLocationId);
stmt.bind(1, storageOccurrence.elementId);
stmt.bind(2, storageOccurrence.sourceLocationId);
executeStatement(stmt);
}
int DatabaseStorage::addError(
const std::string& message,
bool fatal)
int DatabaseStorage::addError(const StorageErrorData& storageErrorData)
{
int id = 0;
{
@@ -506,8 +517,8 @@ namespace sourcetrail
"fatal == ? "
"LIMIT 1;"
);
stmt.bind(1, message.c_str());
stmt.bind(2, fatal);
stmt.bind(1, storageErrorData.message.c_str());
stmt.bind(2, storageErrorData.fatal);
CppSQLite3Query q = executeQuery(stmt);
if (!q.eof() && q.numFields() > 0)
{
@@ -530,10 +541,10 @@ namespace sourcetrail
"VALUES(?, ?, ?, ?, ?);"
);
stmt.bind(1, id);
stmt.bind(2, message.c_str());
stmt.bind(3, fatal);
stmt.bind(4, true);
stmt.bind(5, "");
stmt.bind(2, storageErrorData.message.c_str());
stmt.bind(3, storageErrorData.fatal);
stmt.bind(4, storageErrorData.indexed);
stmt.bind(5, storageErrorData.translationUnit.c_str());
executeStatement(stmt);
id = m_database.lastRowId();
}
@@ -613,4 +624,208 @@ namespace sourcetrail
throw SourcetrailException("Failed to execute query with message \"" + std::string(e.errorMessage()) + "\".");
}
}
template <>
std::vector<StorageEdge> DatabaseStorage::doGetAll<StorageEdge>(const std::string& query) const
{
CppSQLite3Query q = executeQuery(
"SELECT id, type, source_node_id, target_node_id FROM edge " + query + ";"
);
std::vector<StorageEdge> edges;
while (!q.eof())
{
const int id = q.getIntField(0, 0);
const int edgeKind = q.getIntField(1, -1);
const int sourceId = q.getIntField(2, 0);
const int targetId = q.getIntField(3, 0);
if (id != 0 && edgeKind != -1)
{
edges.emplace_back(StorageEdge(id, sourceId, targetId, edgeKind));
}
q.nextRow();
}
return edges;
}
template <>
std::vector<StorageNode> DatabaseStorage::doGetAll<StorageNode>(const std::string& query) const
{
CppSQLite3Query q = executeQuery(
"SELECT id, type, serialized_name FROM node " + query + ";"
);
std::vector<StorageNode> nodes;
while (!q.eof())
{
const int id = q.getIntField(0, 0);
const int type = q.getIntField(1, -1);
const std::string serializedName = q.getStringField(2, "");
if (id != 0 && type != -1)
{
nodes.emplace_back(StorageNode(id, type, serializedName));
}
q.nextRow();
}
return nodes;
}
template <>
std::vector<StorageSymbol> DatabaseStorage::doGetAll<StorageSymbol>(const std::string& query) const
{
CppSQLite3Query q = executeQuery(
"SELECT id, definition_kind FROM symbol " + query + ";"
);
std::vector<StorageSymbol> symbols;
while (!q.eof())
{
const int id = q.getIntField(0, 0);
const int definitionKind = q.getIntField(1, 0);
if (id != 0)
{
symbols.emplace_back(StorageSymbol(id, definitionKind));
}
q.nextRow();
}
return symbols;
}
template <>
std::vector<StorageFile> DatabaseStorage::doGetAll<StorageFile>(const std::string& query) const
{
CppSQLite3Query q = executeQuery(
"SELECT id, path, modification_time, indexed, complete FROM file " + query + ";"
);
std::vector<StorageFile> files;
while (!q.eof())
{
const int id = q.getIntField(0, 0);
const std::string filePath = q.getStringField(1, "");
const std::string modificationTime = q.getStringField(2, "");
const bool indexed = q.getIntField(3, 0);
const bool complete = q.getIntField(4, 0);
if (id != 0)
{
files.emplace_back(StorageFile(id, filePath, modificationTime, indexed, complete));
}
q.nextRow();
}
return files;
}
template <>
std::vector<StorageLocalSymbol> DatabaseStorage::doGetAll<StorageLocalSymbol>(const std::string& query) const
{
CppSQLite3Query q = executeQuery(
"SELECT id, name FROM local_symbol " + query + ";"
);
std::vector<StorageLocalSymbol> localSymbols;
while (!q.eof())
{
const int id = q.getIntField(0, 0);
const std::string name = q.getStringField(1, "");
if (id != 0)
{
localSymbols.emplace_back(StorageLocalSymbol(id, name));
}
q.nextRow();
}
return localSymbols;
}
template <>
std::vector<StorageSourceLocation> DatabaseStorage::doGetAll<StorageSourceLocation>(const std::string& query) const
{
CppSQLite3Query q = executeQuery(
"SELECT id, file_node_id, start_line, start_column, end_line, end_column, type FROM source_location " + query + ";"
);
std::vector<StorageSourceLocation> sourceLocations;
while (!q.eof())
{
const int id = q.getIntField(0, 0);
const int fileNodeId = q.getIntField(1, 0);
const int startLineNumber = q.getIntField(2, -1);
const int startColNumber = q.getIntField(3, -1);
const int endLineNumber = q.getIntField(4, -1);
const int endColNumber = q.getIntField(5, -1);
const int locationKind = q.getIntField(6, -1);
if (id != 0 && fileNodeId != 0 && startLineNumber != -1 && startColNumber != -1 && endLineNumber != -1 &&
endColNumber != -1 && locationKind != -1)
{
sourceLocations.emplace_back(StorageSourceLocation(id, fileNodeId, startLineNumber, startColNumber, endLineNumber, endColNumber, locationKind));
}
q.nextRow();
}
return sourceLocations;
}
template <>
std::vector<StorageOccurrence> DatabaseStorage::doGetAll<StorageOccurrence>(const std::string& query) const
{
CppSQLite3Query q = executeQuery(
"SELECT element_id, source_location_id FROM occurrence " + query + ";"
);
std::vector<StorageOccurrence> occurrences;
while (!q.eof())
{
const int elementId = q.getIntField(0, 0);
const int sourceLocationId = q.getIntField(1, 0);
if (elementId != 0 && sourceLocationId != 0)
{
occurrences.emplace_back(StorageOccurrence(elementId, sourceLocationId));
}
q.nextRow();
}
return occurrences;
}
template <>
std::vector<StorageError> DatabaseStorage::doGetAll<StorageError>(const std::string& query) const
{
CppSQLite3Query q = executeQuery(
"SELECT id, message, fatal, indexed, translation_unit FROM error " + query + ";"
);
std::vector<StorageError> errors;
while (!q.eof())
{
const int id = q.getIntField(0, 0);
const std::string message = q.getStringField(1, "");
const bool fatal = q.getIntField(2, 0);
const bool indexed = q.getIntField(3, 0);
const std::string translationUnit = q.getStringField(4, "");
if (id != 0)
{
errors.emplace_back(StorageError(id, message, translationUnit, fatal, indexed));
}
q.nextRow();
}
return errors;
}
}
+16 -14
View File
@@ -32,6 +32,7 @@
#include "SourceRange.h"
#include "SourcetrailException.h"
#include "SymbolKind.h"
#include "utility.h"
#include "version.h"
namespace sourcetrail
@@ -67,7 +68,7 @@ namespace sourcetrail
{
m_databaseFilePath = databaseFilePath;
m_projectFilePath = databaseFilePath;
m_projectFilePath = databaseFilePath; //FIXME: only find dot after last slash/backslash! otherwise it may be part of the file path
const size_t pos = m_projectFilePath.rfind('.');
if (pos != std::string::npos)
{
@@ -329,7 +330,7 @@ namespace sourcetrail
try
{
m_storage->addSymbol(symbolId, definitionKindToInt(definitionKind));
m_storage->addSymbol(StorageSymbol(symbolId, definitionKindToInt(definitionKind)));
}
catch (const SourcetrailException e)
{
@@ -489,7 +490,7 @@ namespace sourcetrail
try
{
return m_storage->addLocalSymbol(name);
return m_storage->addLocalSymbol(StorageLocalSymbolData(name));
}
catch (const SourcetrailException e)
{
@@ -529,14 +530,14 @@ namespace sourcetrail
try
{
const int fileId = addFile(location.filePath);
const int sourceLocationId = m_storage->addSourceLocation(
const int sourceLocationId = m_storage->addSourceLocation(StorageSourceLocationData(
fileId,
location.startLine,
location.startColumn,
location.endLine,
location.endColumn,
LOCATION_COMMENT
);
locationKindToInt(LOCATION_COMMENT)
));
return true;
}
@@ -557,7 +558,7 @@ namespace sourcetrail
try
{
const int errorId = m_storage->addError(message, fatal);
const int errorId = m_storage->addError(StorageErrorData(message, "", fatal, true));
addSourceLocation(errorId, location, LOCATION_ERROR);
return true;
}
@@ -671,7 +672,7 @@ namespace sourcetrail
{
currentNameHierarchy.nameElements.push_back(nameHierarchy.nameElements[i]);
int nodeId = m_storage->addNode(serializeNameHierarchy(currentNameHierarchy));
int nodeId = m_storage->addNode(StorageNodeData(nodeKindToInt(NODE_UNKNOWN), serializeNameHierarchy(currentNameHierarchy)));
if (parentNodeId != 0)
{
@@ -693,7 +694,8 @@ namespace sourcetrail
const int nodeId = addNodeHierarchy(nameHierarchy);
m_storage->setNodeType(nodeId, nodeKindToInt(NODE_FILE));
m_storage->addFile(nodeId, filePath);
m_storage->addFile(StorageFile(nodeId, filePath, utility::getDateTimeString(time(0)), true, true));
return nodeId;
}
@@ -713,25 +715,25 @@ namespace sourcetrail
throw SourcetrailException("Unable to add edge, because target id is invalid.");
}
return m_storage->addEdge(sourceId, targetId, edgeKindToInt(edgeKind));
return m_storage->addEdge(StorageEdgeData(sourceId, targetId, edgeKindToInt(edgeKind)));
}
void SourcetrailDBWriter::addSourceLocation(int elementId, const SourceRange& location, LocationKind kind)
{
const int fileId = addFile(location.filePath);
const int sourceLocationId = m_storage->addSourceLocation(
const int sourceLocationId = m_storage->addSourceLocation(StorageSourceLocationData(
fileId,
location.startLine,
location.startColumn,
location.endLine,
location.endColumn,
locationKindToInt(kind)
);
));
m_storage->addOccurrence(
m_storage->addOccurrence(StorageOccurrence(
elementId,
sourceLocationId
);
));
}
}
+70
View File
@@ -0,0 +1,70 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "SymbolKind.h"
#include "NodeKind.h"
namespace sourcetrail
{
NodeKind symbolKindToNodeKind(SymbolKind v)
{
switch (v)
{
case SYMBOL_TYPE:
return NODE_TYPE;
case SYMBOL_BUILTIN_TYPE:
return NODE_BUILTIN_TYPE;
case SYMBOL_MODULE:
return NODE_MODULE;
case SYMBOL_NAMESPACE:
return NODE_NAMESPACE;
case SYMBOL_PACKAGE:
return NODE_PACKAGE;
case SYMBOL_STRUCT:
return NODE_STRUCT;
case SYMBOL_CLASS:
return NODE_CLASS;
case SYMBOL_INTERFACE:
return NODE_INTERFACE;
case SYMBOL_ANNOTATION:
return NODE_ANNOTATION;
case SYMBOL_GLOBAL_VARIABLE:
return NODE_GLOBAL_VARIABLE;
case SYMBOL_FIELD:
return NODE_FIELD;
case SYMBOL_FUNCTION:
return NODE_FUNCTION;
case SYMBOL_METHOD:
return NODE_METHOD;
case SYMBOL_ENUM:
return NODE_ENUM;
case SYMBOL_ENUM_CONSTANT:
return NODE_ENUM_CONSTANT;
case SYMBOL_TYPEDEF:
return NODE_TYPEDEF;
case SYMBOL_TEMPLATE_PARAMETER:
return NODE_TEMPLATE_PARAMETER;
case SYMBOL_TYPE_PARAMETER:
return NODE_TYPE_PARAMETER;
case SYMBOL_MACRO:
return NODE_MACRO;
case SYMBOL_UNION:
return NODE_UNION;
}
return NODE_UNKNOWN;
}
}
+1 -11
View File
@@ -16,8 +16,8 @@
#include "utility.h"
#include <ctime>
#include <fstream>
#include <filesystem>
#include "SourcetrailException.h"
@@ -53,16 +53,6 @@ namespace sourcetrail
return content;
}
time_t getFileModificationTime(const std::string& filePath)
{
std::experimental::filesystem::path p(filePath);
auto ftime = std::experimental::filesystem::last_write_time(p);
// assuming system_clock for this demo
// note: not true on MSVC; C++20 will allow portable output
return decltype(ftime)::clock::to_time_t(ftime);
}
std::string getDateTimeString(const time_t& time)
{
std::tm* ptm = std::localtime(&time);
+100
View File
@@ -0,0 +1,100 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() function
#include "catch/catch.hpp"
#include "SourcetrailDBWriter.h"
#include "DatabaseStorage.h"
namespace sourcetrail
{
TEST_CASE("Testing SourcetrailDBWriter")
{
const std::string databasePath = "testing.db";
std::shared_ptr<DatabaseStorage> storage = DatabaseStorage::openDatabase(databasePath);
SourcetrailDBWriter writer;
REQUIRE(writer.getLastError().empty());
writer.open(databasePath);
REQUIRE(writer.getLastError().empty());
writer.clear();
REQUIRE(writer.getLastError().empty());
SECTION("writer is compatible after clearing")
{
REQUIRE(writer.isCompatible());
}
SECTION("writer is empty after clearing")
{
REQUIRE(writer.isEmpty());
}
SECTION("writer can record symbol")
{
NameHierarchy nameSymbol1({ "." , {{ "void", "foo", "()" } } });
int idSymbol1 = writer.recordSymbol(nameSymbol1);
REQUIRE(idSymbol1 != 0);
REQUIRE(writer.getLastError().empty());
SECTION("database contains node after recording plane symbol")
{
std::vector<StorageNode> nodes = storage->getAll<StorageNode>();
REQUIRE(nodes.size() == 1);
}
SECTION("writer does not record symbol twice")
{
int secondIdSymbol1 = writer.recordSymbol(nameSymbol1);
REQUIRE(secondIdSymbol1 == idSymbol1);
REQUIRE(writer.getLastError().empty());
std::vector<StorageNode> nodes = storage->getAll<StorageNode>();
REQUIRE(nodes.size() == 1);
}
SECTION("writer records \"explicit\" symbol definition kind")
{
bool success = writer.recordSymbolDefinitionKind(idSymbol1, DEFINITION_EXPLICIT);
REQUIRE(success);
REQUIRE(writer.getLastError().empty());
std::vector<StorageSymbol> symbols = storage->getAll<StorageSymbol>();
REQUIRE(symbols.size() == 1);
REQUIRE(symbols.front().definitionKind == definitionKindToInt(DEFINITION_EXPLICIT));
}
SECTION("writer records \"class\" symbol kind")
{
bool success = writer.recordSymbolKind(idSymbol1, SYMBOL_CLASS);
REQUIRE(success);
REQUIRE(writer.getLastError().empty());
std::vector<StorageNode> nodes = storage->getAll<StorageNode>();
REQUIRE(nodes.size() == 1);
REQUIRE(nodes.front().nodeKind == symbolKindToNodeKind(SYMBOL_CLASS));
}
}
writer.close();
REQUIRE(writer.getLastError().empty());
}
}