Add budget & transaction (de)serialization and some cmake improvements
Signed-off-by: William Brawner <me@wbrawner.com>
This commit is contained in:
parent
dc7ba2719f
commit
774b90127a
30 changed files with 890 additions and 271 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,3 +1,5 @@
|
|||
build/
|
||||
.kdev4/
|
||||
*.kdev4
|
||||
deps/
|
||||
tags
|
||||
|
|
10
.vimrc
Normal file
10
.vimrc
Normal file
|
@ -0,0 +1,10 @@
|
|||
set colorcolumn=110
|
||||
highlight ColorColumn ctermbg=darkgray
|
||||
augroup project
|
||||
autocmd!
|
||||
autocmd BufRead,BufNewFile *.h,*.c set filetype=c.doxygen
|
||||
augroup END
|
||||
nnoremap <F4> :!mkdir -p build <bar> cmake -B build <bar> make -C build<cr>
|
||||
nnoremap <F4> :!build/PiHelper/pihelper localhost<cr>
|
||||
nnoremap <F9> :!rm -rf build<cr>
|
||||
let &path.="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include,"
|
1
budget.json
Normal file
1
budget.json
Normal file
|
@ -0,0 +1 @@
|
|||
{"id":"Gbhqm79yC8NereIONtq7W2Mf9MD2y1AU","name":"Monthly Budget","description":"Monthly expenses"}
|
3
include/twigs/api_service.h
Normal file
3
include/twigs/api_service.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
#ifndef API_SERVICE_H
|
||||
#define API_SERVICE_H
|
||||
#endif
|
|
@ -1,33 +1,28 @@
|
|||
#ifndef BUDGET_H
|
||||
#define BUDGET_H
|
||||
#include <string>
|
||||
#include "hashable.h"
|
||||
#include "identifiable.h"
|
||||
#include "serializable.h"
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Budget: public Identifiable, public Hashable {
|
||||
private:
|
||||
class Budget : public Identifiable, public Hashable, public Serializable {
|
||||
private:
|
||||
string id;
|
||||
string name;
|
||||
string description;
|
||||
|
||||
public:
|
||||
string getName() {
|
||||
return this->name;
|
||||
}
|
||||
|
||||
void setName(string name) {
|
||||
this->name = name;
|
||||
}
|
||||
|
||||
string getDescription() {
|
||||
return this->description;
|
||||
}
|
||||
|
||||
void setDescription(string description) {
|
||||
this->description = description;
|
||||
}
|
||||
|
||||
public:
|
||||
Budget();
|
||||
Budget(std::string id, std::string name, std::string description);
|
||||
string getId() override;
|
||||
string getName();
|
||||
void setName(string name);
|
||||
string getDescription();
|
||||
void setDescription(string description);
|
||||
string hash() override;
|
||||
string serialize() override;
|
||||
static Budget deserialize(std::string data);
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -1,64 +1,38 @@
|
|||
#ifndef CATEGORY_H
|
||||
#define CATEGORY_H
|
||||
#include <string>
|
||||
#ifndef CATEGORY_H
|
||||
#include "hashable.h"
|
||||
#include "identifiable.h"
|
||||
#include "serializable.h"
|
||||
#include <string>
|
||||
|
||||
class Category: public Identifiable, public Hashable {
|
||||
private:
|
||||
class Category : public Identifiable, public Hashable, public Serializable {
|
||||
private:
|
||||
std::string id;
|
||||
std::string name;
|
||||
std::string description;
|
||||
long amount;
|
||||
unsigned int amount;
|
||||
bool expense;
|
||||
bool archived;
|
||||
std::string budgetId;
|
||||
|
||||
public:
|
||||
std::string getId() {
|
||||
return this->id;
|
||||
}
|
||||
|
||||
std::string getName() {
|
||||
return this->name;
|
||||
}
|
||||
|
||||
void setName(std::string name) {
|
||||
this->name = name;
|
||||
}
|
||||
|
||||
std::string getDescription() {
|
||||
return this->description;
|
||||
}
|
||||
|
||||
void setDescription(std::string description) {
|
||||
this->description = description;
|
||||
}
|
||||
|
||||
long getAmount() {
|
||||
return this->amount;
|
||||
}
|
||||
|
||||
void setAmount(long amount) {
|
||||
this->amount = amount;
|
||||
}
|
||||
|
||||
bool isExpense() {
|
||||
return this->expense;
|
||||
}
|
||||
|
||||
void setExpense(bool expense) {
|
||||
this->expense = expense;
|
||||
}
|
||||
|
||||
bool isArchived() {
|
||||
return this->archived;
|
||||
}
|
||||
|
||||
void setArchived(bool archived) {
|
||||
this->archived = archived;
|
||||
}
|
||||
|
||||
public:
|
||||
Category();
|
||||
Category(std::string id, std::string name, std::string budgetId,
|
||||
std::string description = "", unsigned int amount = 0,
|
||||
bool expense = true, bool archived = false);
|
||||
std::string getId() override;
|
||||
std::string getName();
|
||||
void setName(std::string name);
|
||||
std::string getDescription();
|
||||
void setDescription(std::string description);
|
||||
unsigned int getAmount();
|
||||
void setAmount(unsigned int amount);
|
||||
bool isExpense();
|
||||
void setExpense(bool expense);
|
||||
bool isArchived();
|
||||
void setArchived(bool archived);
|
||||
std::string hash() override;
|
||||
string serialize() override;
|
||||
static Categpry deserialize(std::string data);
|
||||
};
|
||||
#endif
|
||||
|
|
4
include/twigs/db_service.h
Normal file
4
include/twigs/db_service.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
#ifndef DB_SERVICE_H
|
||||
#define DB_SERVICE_H
|
||||
|
||||
#endif
|
|
@ -3,15 +3,7 @@
|
|||
#include <string>
|
||||
|
||||
class Identifiable {
|
||||
private:
|
||||
std::string id;
|
||||
|
||||
public:
|
||||
std::string getId() {
|
||||
return this->id;
|
||||
}
|
||||
void setId(std::string id) {
|
||||
this->id = id;
|
||||
}
|
||||
virtual std::string getId() = 0;
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -13,6 +13,7 @@ enum Permission {
|
|||
|
||||
class UserPermission: public Identifiable {
|
||||
private:
|
||||
std::string id;
|
||||
std::string userId;
|
||||
std::string budgetId;
|
||||
Permission permission;
|
||||
|
@ -23,6 +24,8 @@ class UserPermission: public Identifiable {
|
|||
this->budgetId = budgetId;
|
||||
}
|
||||
|
||||
std::string getId() override;
|
||||
|
||||
std::string getUserId() {
|
||||
return this->userId;
|
||||
}
|
||||
|
|
9
include/twigs/serializable.h
Normal file
9
include/twigs/serializable.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef SERIALIZABLE_H
|
||||
#define SERIALIZABLE_H
|
||||
#include <string>
|
||||
|
||||
class Serializable {
|
||||
public:
|
||||
virtual std::string serialize() = 0;
|
||||
};
|
||||
#endif
|
|
@ -1,113 +1,51 @@
|
|||
#ifndef TRANSACTION_H
|
||||
#define TRANSACTION_H
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include "hashable.h"
|
||||
#include "identifiable.h"
|
||||
#include "serializable.h"
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <time.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Transaction: public Identifiable, public Hashable {
|
||||
private:
|
||||
string name;
|
||||
string description;
|
||||
class Transaction : public Identifiable, public Hashable, public Serializable {
|
||||
private:
|
||||
std::string id;
|
||||
std::string name;
|
||||
std::string description;
|
||||
tm date;
|
||||
long amount;
|
||||
unsigned int amount;
|
||||
bool expense;
|
||||
bool archived;
|
||||
string categoryId;
|
||||
string budgetId;
|
||||
std::string categoryId;
|
||||
std::string budgetId;
|
||||
std::string createdBy;
|
||||
|
||||
public:
|
||||
Transaction() {
|
||||
this->name = "";
|
||||
this->description = "";
|
||||
time_t now = time(0);
|
||||
this->date = *gmtime(&now);
|
||||
this->amount = 0;
|
||||
this->expense = true;
|
||||
this->archived = false;
|
||||
}
|
||||
|
||||
string getName() {
|
||||
return this->name;
|
||||
}
|
||||
|
||||
void setName(string name) {
|
||||
this->name = name;
|
||||
}
|
||||
|
||||
string getDescription() {
|
||||
return this->description;
|
||||
}
|
||||
|
||||
void setDescription(string description) {
|
||||
this->description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date as a string formatted as YYYY-MM-ddTHH:mm:ssZ
|
||||
*/
|
||||
string getDate() {
|
||||
char date[25];
|
||||
snprintf(
|
||||
date,
|
||||
21,
|
||||
"%04d-%02d-%02dT%02d:%02d:%02dZ",
|
||||
this->date.tm_year,
|
||||
this->date.tm_mon + 1,
|
||||
this->date.tm_mday,
|
||||
this->date.tm_hour,
|
||||
this->date.tm_min,
|
||||
this->date.tm_sec
|
||||
);
|
||||
return date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the date using YYYY-MM-ddTHH:mm:ssZ format
|
||||
*/
|
||||
void setDate(string date) {
|
||||
//TODO: Handle exceptions
|
||||
int year = stoi(date.substr(0,4));
|
||||
int mon = stoi(date.substr(5, 2));
|
||||
int day = stoi(date.substr(8, 2));
|
||||
int hours = stoi(date.substr(11, 2));
|
||||
int min = stoi(date.substr(14, 2));
|
||||
int sec = stoi(date.substr(17, 2));
|
||||
this->date.tm_year = year;
|
||||
this->date.tm_mon = mon - 1;
|
||||
this->date.tm_mday = day;
|
||||
this->date.tm_hour = hours;
|
||||
this->date.tm_min = min;
|
||||
this->date.tm_sec = sec;
|
||||
}
|
||||
|
||||
long getAmount() {
|
||||
return this->amount;
|
||||
}
|
||||
|
||||
void setAmount(long amount) {
|
||||
this->amount = amount;
|
||||
}
|
||||
|
||||
bool isExpense() {
|
||||
return this->expense;
|
||||
}
|
||||
|
||||
void setExpense(bool expense) {
|
||||
this->expense = expense;
|
||||
}
|
||||
|
||||
bool isArchived() {
|
||||
return this->archived;
|
||||
}
|
||||
|
||||
void setArchived(bool archived) {
|
||||
this->archived = archived;
|
||||
}
|
||||
|
||||
string hash() override;
|
||||
public:
|
||||
Transaction();
|
||||
Transaction(std::string id, std::string name, tm date, std::string createdBy,
|
||||
unsigned int amount = 0, std::string description = "",
|
||||
bool expense = true, std::string categoryId = "",
|
||||
std::string budgetId = "");
|
||||
std::string getId() override;
|
||||
std::string getName();
|
||||
void setName(std::string name);
|
||||
std::string getDescription();
|
||||
void setDescription(std::string description);
|
||||
tm getDate();
|
||||
void setDate(tm date);
|
||||
unsigned int getAmount();
|
||||
void setAmount(unsigned int amount);
|
||||
bool isExpense();
|
||||
void setExpense(bool expense);
|
||||
bool isArchived();
|
||||
void setArchived(bool archived);
|
||||
std::string getCategoryId();
|
||||
void setCategoryId(std::string categoryId);
|
||||
std::string getBudgetId();
|
||||
void setBudgetId(std::string budgetId);
|
||||
std::string getCreatedBy();
|
||||
void setCreatedBy(std::string createdBy);
|
||||
std::string hash() override;
|
||||
std::string serialize() override;
|
||||
static Transaction deserialize(std::string data);
|
||||
};
|
||||
#endif
|
||||
|
|
13
include/twigs/transaction_repository.h
Normal file
13
include/twigs/transaction_repository.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#define TRANSACTION_REPOSITORY_H
|
||||
#ifndef TRANSACTION_REPOSITORY_H
|
||||
#include "transaction.h"
|
||||
|
||||
class TransactionRepository {
|
||||
public:
|
||||
Transaction findById(std::string id);
|
||||
Transaction *findAll(std::string *budgetIds, std::string *categoryIds,
|
||||
std::string *from, std::string *to, int count, int page);
|
||||
Transaction save(Transaction transaction);
|
||||
void remove(Transaction transaction);
|
||||
};
|
||||
#endif
|
|
@ -5,11 +5,13 @@
|
|||
|
||||
class User: public Identifiable {
|
||||
private:
|
||||
std::string id;
|
||||
std::string name;
|
||||
std::string email;
|
||||
std::string avatar;
|
||||
|
||||
public:
|
||||
std::string getId() override;
|
||||
std::string getName();
|
||||
void setName(std::string name);
|
||||
std::string getEmail();
|
||||
|
|
12
include/twigs/utils.h
Normal file
12
include/twigs/utils.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
#include <string>
|
||||
|
||||
namespace util {
|
||||
std::string randomId();
|
||||
std::string hash(std::string data);
|
||||
tm parseDate(std::string str);
|
||||
std::string printDate(tm date);
|
||||
} // namespace util
|
||||
|
||||
#endif
|
198
scripts/build-android
Executable file
198
scripts/build-android
Executable file
|
@ -0,0 +1,198 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Configure the following variables according to your needs
|
||||
|
||||
NDK_VERSION="21.3.6528147"
|
||||
OPENSSL_TAG_VERSION="OpenSSL_1_1_1g "
|
||||
CURL_TAG_VERSION="master "
|
||||
JSONCPP_TAG_VERSION="master"
|
||||
ANDROID_ARCHS="arm arm64 x86 x86_64"
|
||||
NDK=$HOME/Android/Sdk/ndk/$NDK_VERSION
|
||||
MIN_SDK_VERSION=23 # Can't go any lower unfortunately. See the cURL docs for more info.
|
||||
TARGET_SDK_VERSION=29
|
||||
|
||||
# Edit below at your own risk
|
||||
|
||||
get_abi() {
|
||||
case $1 in
|
||||
"arm")
|
||||
echo -n "armeabi-v7a"
|
||||
;;
|
||||
"arm64")
|
||||
echo -n "arm64-v8a"
|
||||
;;
|
||||
"x86")
|
||||
echo -n "x86"
|
||||
;;
|
||||
"x86_64")
|
||||
echo -n "x86_64"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
make_openssl() {
|
||||
(
|
||||
cd deps
|
||||
test -d openssl || git clone --branch $OPENSSL_TAG_VERSION https://github.com/openssl/openssl.git
|
||||
for ARCH in $ANDROID_ARCHS; do
|
||||
(
|
||||
export PREFIX="$BUILD_DIR/android/$ARCH"
|
||||
mkdir -p "$PREFIX"
|
||||
cd openssl
|
||||
git checkout $OPENSSL_TAG_VERSION
|
||||
make clean
|
||||
export ANDROID_NDK_HOME=$NDK
|
||||
export ANDROID_NDK_ROOT=$NDK
|
||||
export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$ANDROID_NDK_HOME/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin:$PATH
|
||||
./Configure \
|
||||
--prefix="$PREFIX" \
|
||||
-D__ANDROID_API__=$TARGET_SDK_VERSION \
|
||||
no-shared \
|
||||
android-$ARCH
|
||||
make install_dev
|
||||
)
|
||||
done
|
||||
)
|
||||
}
|
||||
|
||||
make_curl() {
|
||||
(
|
||||
cd deps
|
||||
test -d curl || git clone --branch $CURL_TAG_VERSION https://github.com/curl/curl.git
|
||||
for ARCH in $ANDROID_ARCHS; do
|
||||
(
|
||||
export PREFIX="$BUILD_DIR/android/$ARCH"
|
||||
mkdir -p "$PREFIX"
|
||||
cd curl
|
||||
git checkout $CURL_TAG_VERSION
|
||||
test -f configure || ./buildconf
|
||||
export HOST_TAG=linux-x86_64
|
||||
export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/$HOST_TAG
|
||||
case $ARCH in
|
||||
"arm")
|
||||
export CURL_ARCH="arm-linux-androideabi"
|
||||
export CLANG="armv7a-linux-androideabi"
|
||||
;;
|
||||
"arm64")
|
||||
export CURL_ARCH="aarch64-linux-android"
|
||||
export CLANG=$CURL_ARCH
|
||||
;;
|
||||
"x86")
|
||||
export CURL_ARCH="i686-linux-android"
|
||||
export CLANG=$CURL_ARCH
|
||||
;;
|
||||
"x86_64")
|
||||
export CURL_ARCH="x86_64-linux-android"
|
||||
export CLANG=$CURL_ARCH
|
||||
;;
|
||||
esac
|
||||
export AR=$TOOLCHAIN/bin/$CURL_ARCH-ar
|
||||
export AS=$TOOLCHAIN/bin/$CURL_ARCH-as
|
||||
export CC=$TOOLCHAIN/bin/${CLANG}${MIN_SDK_VERSION}-clang
|
||||
export CXX=$TOOLCHAIN/bin/${CLANG}${MIN_SDK_VERSION}-clang++
|
||||
export LD=$TOOLCHAIN/bin/$CURL_ARCH-ld
|
||||
export RANLIB=$TOOLCHAIN/bin/$CURL_ARCH-ranlib
|
||||
export STRIP=$TOOLCHAIN/bin/$CURL_ARCH-strip
|
||||
make clean
|
||||
./configure --prefix="$PREFIX" \
|
||||
--host $CURL_ARCH \
|
||||
--with-pic \
|
||||
--disable-shared \
|
||||
--with-ssl="$PREFIX"
|
||||
make install
|
||||
)
|
||||
done
|
||||
)
|
||||
}
|
||||
|
||||
make_jsoncpp() {
|
||||
(
|
||||
cd deps
|
||||
test -d jsoncpp || git clone --branch $JSONCPP_TAG_VERSION https://github.com/open-source-parsers/jsoncpp
|
||||
for ARCH in $ANDROID_ARCHS; do
|
||||
(
|
||||
export PREFIX="$BUILD_DIR/android/$ARCH"
|
||||
mkdir -p "$PREFIX"
|
||||
cd jsoncpp
|
||||
git checkout $JSONCPP_TAG_VERSION
|
||||
test -d $ARCH && rm -rf $ARCH
|
||||
mkdir $ARCH
|
||||
pushd $ARCH
|
||||
export ABI="$(get_abi $ARCH)"
|
||||
#TODO: CMake is deprecated, this should use meson/ninja
|
||||
cmake \
|
||||
-DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \
|
||||
-DANDROID_ABI=$ABI \
|
||||
-DANDROID_NATIVE_API_LEVEL=$MIN_SDK_VERSION \
|
||||
-DCMAKE_INSTALL_PREFIX=$PREFIX \
|
||||
-DBUILD_OBJECT_LIBS=OFF \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DJSONCPP_WITH_TESTS=OFF \
|
||||
-DBUILD_STATIC_LIBS=ON \
|
||||
..
|
||||
make
|
||||
make install
|
||||
)
|
||||
done
|
||||
)
|
||||
}
|
||||
|
||||
make_twigs() {
|
||||
(
|
||||
for ARCH in $ANDROID_ARCHS; do
|
||||
(
|
||||
export PREFIX="$BUILD_DIR/android/$ARCH"
|
||||
export ABI="$(get_abi $ARCH)"
|
||||
mkdir -p "$PREFIX"
|
||||
cd "$BUILD_DIR"
|
||||
test -d $ARCH && rm -rf $ARCH
|
||||
mkdir $ARCH
|
||||
pushd $ARCH
|
||||
cmake \
|
||||
-DCMAKE_FIND_ROOT_PATH=$PREFIX \
|
||||
-DCMAKE_INCLUDE_PATH=$PREFIX/include \
|
||||
-DCMAKE_PREFIX_PATH=$PREFIX \
|
||||
-DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \
|
||||
-DANDROID_ABI=$ABI \
|
||||
-DANDROID_NATIVE_API_LEVEL=$MIN_SDK_VERSION \
|
||||
-DCMAKE_INSTALL_PREFIX=$PREFIX \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DBUILD_TESTING=OFF \
|
||||
-DBUILD_STATIC_LIBS=ON \
|
||||
../..
|
||||
make
|
||||
make install
|
||||
)
|
||||
done
|
||||
)
|
||||
}
|
||||
|
||||
package() {
|
||||
for ARCH in $ANDROID_ARCHS; do
|
||||
(
|
||||
export ABI="$(get_abi $ARCH)"
|
||||
cd $BUILD_DIR/android
|
||||
cp -r $ARCH/include .
|
||||
mv $ARCH/lib/*.a $ARCH/lib/*.la $ARCH/
|
||||
rm -rf $ARCH/{bin,lib,include,share}
|
||||
if [ "$ARCH" != "$ABI" ]; then
|
||||
mv $ARCH $ABI
|
||||
fi
|
||||
)
|
||||
done
|
||||
}
|
||||
|
||||
(
|
||||
if [ "$(dirname $0)" == "." ]; then
|
||||
cd ..
|
||||
fi
|
||||
test -d deps || mkdir deps
|
||||
export BUILD_DIR="$PWD/build"
|
||||
test -d "$BUILD_DIR" || mkdir -p "$BUILD_DIR"
|
||||
make_openssl
|
||||
make_curl
|
||||
make_jsoncpp
|
||||
make_twigs
|
||||
package
|
||||
)
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
add_subdirectory(libtwigs)
|
||||
|
||||
option(TWIGS_TESTS "Build tests for Twigs" ON)
|
||||
option(BUILD_TESTING "Build tests for Twigs" ON)
|
||||
|
||||
if (TWIGS_TESTS)
|
||||
if (BUILD_TESTING)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
|
|
@ -25,28 +25,41 @@ set(PUBLIC_HEADERS
|
|||
${TWIGS_INCLUDE_DIR}/twigs/hashable.h
|
||||
${TWIGS_INCLUDE_DIR}/twigs/identifiable.h
|
||||
${TWIGS_INCLUDE_DIR}/twigs/permission.h
|
||||
${TWIGS_INCLUDE_DIR}/twigs/serializable.h
|
||||
${TWIGS_INCLUDE_DIR}/twigs/transaction.h
|
||||
${TWIGS_INCLUDE_DIR}/twigs/user.h
|
||||
${TWIGS_INCLUDE_DIR}/twigs/utils.h
|
||||
)
|
||||
|
||||
set(TWIGS_SOURCES
|
||||
budget.cpp
|
||||
#category.cpp
|
||||
transaction.cpp
|
||||
utils.cpp
|
||||
#twigs.cpp
|
||||
#user.cpp
|
||||
)
|
||||
|
||||
#if (NOT TARGET CURL)
|
||||
#find_library(
|
||||
#CURL
|
||||
#NAMES curl libcurl
|
||||
#PATHS /usr/local/lib /usr/local/lib64 /usr/lib /usr/lib64 /lib
|
||||
#)
|
||||
#if (NOT CURL)
|
||||
#message(SEND_ERROR "Did not find curl")
|
||||
#endif()
|
||||
#endif()
|
||||
if (NOT TARGET CURL)
|
||||
find_library(
|
||||
CURL
|
||||
NAMES curl libcurl
|
||||
PATHS /usr/local/lib /usr/local/lib64 /usr/lib /usr/lib64 /lib
|
||||
)
|
||||
if (NOT CURL)
|
||||
message(SEND_ERROR "Did not find curl")
|
||||
endif()
|
||||
endif()
|
||||
if (NOT TARGET JSONCPP)
|
||||
find_library(
|
||||
JSONCPP
|
||||
NAMES jsoncpp libjsoncpp
|
||||
PATHS /usr/local/lib /usr/local/lib64 /usr/lib /usr/lib64 /lib
|
||||
)
|
||||
if (NOT JSONCPP)
|
||||
message(SEND_ERROR "Did not find jsoncpp")
|
||||
endif()
|
||||
endif()
|
||||
#if (NOT TARGET JSONC)
|
||||
#find_library(
|
||||
#JSONC
|
||||
|
@ -57,31 +70,28 @@ set(TWIGS_SOURCES
|
|||
#message(SEND_ERROR "Did not find json-c")
|
||||
#endif()
|
||||
#endif()
|
||||
#if (NOT TARGET CRYPTO)
|
||||
#find_library(
|
||||
#CRYPTO
|
||||
#NAMES crypto libcrypto
|
||||
#PATHS /usr/local/lib /usr/local/lib64 /usr/lib /usr/lib64 /lib
|
||||
#)
|
||||
#if (NOT CRYPTO)
|
||||
#message(SEND_ERROR "Did not find OpenSSL")
|
||||
#endif()
|
||||
#endif()
|
||||
#if (NOT TARGET OPENSSL)
|
||||
#find_library(
|
||||
#OPENSSL
|
||||
#NAMES ssl libssl
|
||||
#PATHS /usr/local/lib /usr/local/lib64 /usr/lib /usr/lib64 /lib
|
||||
#)
|
||||
#if (NOT OPENSSL)
|
||||
#message(SEND_ERROR "Did not find OpenSSL")
|
||||
#endif()
|
||||
#endif()
|
||||
if (NOT TARGET CRYPTO)
|
||||
find_library(
|
||||
CRYPTO
|
||||
NAMES crypto libcrypto
|
||||
PATHS /usr/local/lib /usr/local/lib64 /usr/lib /usr/lib64 /lib
|
||||
)
|
||||
if (NOT CRYPTO)
|
||||
message(SEND_ERROR "Did not find OpenSSL")
|
||||
endif()
|
||||
endif()
|
||||
if (NOT TARGET OPENSSL)
|
||||
find_library(
|
||||
OPENSSL
|
||||
NAMES ssl libssl
|
||||
PATHS /usr/local/lib /usr/local/lib64 /usr/lib /usr/lib64 /lib
|
||||
)
|
||||
if (NOT OPENSSL)
|
||||
message(SEND_ERROR "Did not find OpenSSL")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(TWIGS_STATIC "Build Twigs as a static library" ON)
|
||||
option(TWIGS_SHARED "Build Twigs as a shared library" OFF)
|
||||
|
||||
if (TWIGS_STATIC)
|
||||
if (BUILD_SHARED_LIBS)
|
||||
add_library(libtwigs SHARED
|
||||
${TWIGS_SOURCES}
|
||||
${PUBLIC_HEADERS}
|
||||
|
@ -93,12 +103,20 @@ else()
|
|||
)
|
||||
endif()
|
||||
|
||||
target_include_directories(libtwigs PRIVATE
|
||||
target_include_directories(libtwigs PUBLIC
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${TWIGS_INCLUDE_DIR}>
|
||||
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include/twigs>
|
||||
SYSTEM ${CMAKE_INCLUDE_PATH}
|
||||
SYSTEM /usr/local/include
|
||||
)
|
||||
|
||||
target_link_libraries(libtwigs ${JSONCPP}
|
||||
${CURL}
|
||||
${CRYPTO}
|
||||
${OPENSSL}
|
||||
)
|
||||
|
||||
set_target_properties(libtwigs PROPERTIES
|
||||
OUTPUT_NAME "twigs"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
|
@ -106,12 +124,8 @@ set_target_properties(libtwigs PROPERTIES
|
|||
)
|
||||
|
||||
install(TARGETS libtwigs
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
OBJECTS DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
)
|
||||
|
||||
#target_link_libraries(twigs ${CURL}
|
||||
#${JSONC}
|
||||
#${CRYPTO}
|
||||
#${OPENSSL}
|
||||
#)
|
||||
|
|
|
@ -1,6 +1,51 @@
|
|||
#include <twigs/budget.h>
|
||||
#include <string>
|
||||
#include <twigs/budget.h>
|
||||
#include <twigs/utils.h>
|
||||
#include <json/json.h>
|
||||
|
||||
std::string Budget::hash() {
|
||||
return "";
|
||||
Budget::Budget() : Budget(util::randomId(), "", "") {}
|
||||
|
||||
Budget::Budget(std::string id, std::string name, std::string description)
|
||||
: id(id), name(name), description(description) {}
|
||||
|
||||
std::string Budget::getId() { return this->id; }
|
||||
|
||||
string Budget::getName() { return this->name; }
|
||||
|
||||
void Budget::setName(string name) { this->name = name; }
|
||||
|
||||
string Budget::getDescription() { return this->description; }
|
||||
|
||||
void Budget::setDescription(string description) {
|
||||
this->description = description;
|
||||
}
|
||||
|
||||
std::string Budget::serialize() {
|
||||
Json::Value budget;
|
||||
budget["id"] = this->getId();
|
||||
budget["name"] = this->getName();
|
||||
budget["description"] = this->getDescription();
|
||||
Json::StreamWriterBuilder builder;
|
||||
builder["indentation"] = "";
|
||||
return Json::writeString(builder, budget);
|
||||
}
|
||||
|
||||
Budget Budget::deserialize(std::string data) {
|
||||
Json::CharReaderBuilder builder;
|
||||
Json::Value root;
|
||||
if (!builder.newCharReader()->parse(&data[0], &data[0] + data.size(), &root,
|
||||
NULL)) {
|
||||
// TODO: Log errors
|
||||
// std::cout << "Failed to create budget from JSON" << "\n";
|
||||
throw 5;
|
||||
}
|
||||
std::string id = root.get("id", "").asString();
|
||||
if (id == "") {
|
||||
throw 5;
|
||||
}
|
||||
std::string name = root.get("name", "").asString();
|
||||
std::string description = root.get("description", "").asString();
|
||||
return Budget(id, name, description);
|
||||
}
|
||||
|
||||
string Budget::hash() { return util::hash(serialize()); }
|
||||
|
|
76
src/libtwigs/category.cpp
Normal file
76
src/libtwigs/category.cpp
Normal file
|
@ -0,0 +1,76 @@
|
|||
#include <twigs/category.h>
|
||||
#include <twigs/utils.h>
|
||||
|
||||
Category::Category() : Category(util::randomId(), "", "") {}
|
||||
|
||||
Category::Category(std::string id, std::string name, std::string budgetId,
|
||||
std::string description, unsigned int amount, bool expense,
|
||||
bool archived)
|
||||
: id(id), name(name), budgetId(budgetId), description(description),
|
||||
amount(amount), expense(expense), archived(archived) {}
|
||||
|
||||
std::string Category::getId() { return this->id; }
|
||||
|
||||
std::string Category::getName() { return this->name; }
|
||||
|
||||
void Category::setName(std::string name) { this->name = name; }
|
||||
|
||||
std::string Category::getDescription() { return this->description; }
|
||||
|
||||
void Category::setDescription(std::string description) {
|
||||
this->description = description;
|
||||
}
|
||||
|
||||
long Category::getAmount() { return this->amount; }
|
||||
|
||||
void Category::setAmount(long amount) { this->amount = amount; }
|
||||
|
||||
bool Category::isExpense() { return this->expense; }
|
||||
|
||||
void Category::setExpense(bool expense) { this->expense = expense; }
|
||||
|
||||
bool Category::isArchived() { return this->archived; }
|
||||
|
||||
void Category::setArchived(bool archived) { this->archived = archived; }
|
||||
|
||||
std::string Category::getBudgetId() { return this->budgetId; }
|
||||
|
||||
void Category::setBudgetId(std::string budgetId) { this->budgetId = budgetId; }
|
||||
|
||||
std::string Category::serialize() {
|
||||
Json::Value category;
|
||||
category["id"] = this->getId();
|
||||
category["name"] = this->getName();
|
||||
category["description"] = this->getDescription();
|
||||
category["amount"] = this->getAmount();
|
||||
category["expense"] = this->isExpense();
|
||||
category["archived"] = this->isArchived();
|
||||
category["budgetId"] = this->getBudgetId();
|
||||
Json::StreamWriterBuilder builder;
|
||||
builder["indentation"] = "";
|
||||
return Json::writeString(builder, transaction);
|
||||
}
|
||||
|
||||
Category Category::deserialize(std::string data) {
|
||||
Json::CharReaderBuilder builder;
|
||||
Json::Value root;
|
||||
if (!builder.newCharReader()->parse(&data[0], &data[0] + data.size(), &root,
|
||||
NULL)) {
|
||||
// TODO: Log errors
|
||||
// std::cout << "Failed to create transaction from JSON" << "\n";
|
||||
throw 5;
|
||||
}
|
||||
std::string id = root.get("id", "").asString();
|
||||
if (id == "") {
|
||||
throw 5;
|
||||
}
|
||||
std::string name = root.get("name", "").asString();
|
||||
std::string description = root.get("description", "").asString();
|
||||
long amount = root.get("amount", 0).asUInt();
|
||||
bool expense = root.get("expense", true).asBool();
|
||||
bool archived = root.get("archived", true).asBool();
|
||||
std::string budgetId = root.get("budgetId", "").asString();
|
||||
return Category(id, name, description);
|
||||
}
|
||||
|
||||
string Category::hash() { return util::hash(serialize()); }
|
|
@ -1,8 +1,105 @@
|
|||
#include <json/json.h>
|
||||
#include <twigs/serializable.h>
|
||||
#include <twigs/transaction.h>
|
||||
#include <twigs/utils.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
string Transaction::hash() {
|
||||
throw 5;
|
||||
// return "";
|
||||
tm *now() {
|
||||
time_t now = time(NULL);
|
||||
return gmtime(&now);
|
||||
}
|
||||
|
||||
Transaction::Transaction() : Transaction(util::randomId(), "", *now(), "") {}
|
||||
|
||||
Transaction::Transaction(std::string id, std::string name, tm date,
|
||||
std::string createdBy, unsigned int amount,
|
||||
std::string description, bool expense,
|
||||
std::string categoryId, std::string budgetId)
|
||||
: id(id), name(name), description(description), date(date), amount(amount),
|
||||
expense(expense), categoryId(categoryId), budgetId(budgetId),
|
||||
createdBy(createdBy) {}
|
||||
|
||||
string Transaction::getId() { return this->id; }
|
||||
|
||||
string Transaction::getName() { return this->name; }
|
||||
|
||||
void Transaction::setName(std::string name) { this->name = name; }
|
||||
|
||||
string Transaction::getDescription() { return this->description; }
|
||||
|
||||
void Transaction::setDescription(string description) {
|
||||
this->description = description;
|
||||
}
|
||||
|
||||
tm Transaction::getDate() { return this->date; }
|
||||
|
||||
void Transaction::setDate(tm date) { this->date = date; }
|
||||
|
||||
unsigned int Transaction::getAmount() { return this->amount; }
|
||||
|
||||
void Transaction::setAmount(unsigned int amount) { this->amount = amount; }
|
||||
|
||||
bool Transaction::isExpense() { return this->expense; }
|
||||
|
||||
void Transaction::setExpense(bool expense) { this->expense = expense; }
|
||||
|
||||
string Transaction::getCategoryId() { return this->categoryId; }
|
||||
|
||||
void Transaction::setCategoryId(string categoryId) {
|
||||
this->categoryId = categoryId;
|
||||
}
|
||||
|
||||
string Transaction::getBudgetId() { return this->budgetId; }
|
||||
|
||||
void Transaction::setBudgetId(string budgetId) { this->budgetId = budgetId; }
|
||||
|
||||
string Transaction::getCreatedBy() { return this->createdBy; }
|
||||
|
||||
void Transaction::setCreatedBy(string createdBy) {
|
||||
this->createdBy = createdBy;
|
||||
}
|
||||
|
||||
std::string Transaction::serialize() {
|
||||
Json::Value transaction;
|
||||
transaction["id"] = this->getId();
|
||||
transaction["title"] = this->getName();
|
||||
transaction["description"] = this->getDescription();
|
||||
transaction["date"] = util::printDate(this->getDate());
|
||||
transaction["amount"] = this->getAmount();
|
||||
transaction["expense"] = this->isExpense();
|
||||
transaction["budgetId"] = this->getBudgetId();
|
||||
transaction["categoryId"] = this->getCategoryId();
|
||||
transaction["createdBy"] = this->getCreatedBy();
|
||||
Json::StreamWriterBuilder builder;
|
||||
builder["indentation"] = "";
|
||||
return Json::writeString(builder, transaction);
|
||||
}
|
||||
|
||||
Transaction Transaction::deserialize(std::string data) {
|
||||
Json::CharReaderBuilder builder;
|
||||
Json::Value root;
|
||||
if (!builder.newCharReader()->parse(&data[0], &data[0] + data.size(), &root,
|
||||
NULL)) {
|
||||
// TODO: Log errors
|
||||
// std::cout << "Failed to create transaction from JSON" << "\n";
|
||||
throw 5;
|
||||
}
|
||||
std::string id = root.get("id", "").asString();
|
||||
if (id == "") {
|
||||
throw 5;
|
||||
}
|
||||
std::string name = root.get("title", "").asString();
|
||||
std::string description = root.get("description", "").asString();
|
||||
std::string dateStr = root.get("date", "").asString();
|
||||
tm date = util::parseDate(dateStr);
|
||||
long amount = root.get("amount", 0).asUInt();
|
||||
bool expense = root.get("expense", true).asBool();
|
||||
std::string budgetId = root.get("budgetId", "").asString();
|
||||
std::string categoryId = root.get("categoryId", "").asString();
|
||||
std::string createdBy = root.get("createdBy", "").asString();
|
||||
return Transaction(id, name, date, createdBy, amount, description, expense,
|
||||
categoryId, budgetId);
|
||||
}
|
||||
|
||||
string Transaction::hash() { return util::hash(serialize()); }
|
||||
|
|
61
src/libtwigs/utils.cpp
Normal file
61
src/libtwigs/utils.cpp
Normal file
|
@ -0,0 +1,61 @@
|
|||
#include <random>
|
||||
#include <twigs/utils.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
namespace util {
|
||||
std::string randomId() {
|
||||
const std::string CHARACTERS =
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
const int ID_LEN = 32;
|
||||
|
||||
std::random_device rd;
|
||||
std::mt19937 engine(rd());
|
||||
std::uniform_int_distribution<> distribution(0, CHARACTERS.size() - 1);
|
||||
|
||||
std::string random_string;
|
||||
|
||||
for (std::size_t i = 0; i < ID_LEN; ++i) {
|
||||
random_string += CHARACTERS[distribution(engine)];
|
||||
}
|
||||
|
||||
return random_string;
|
||||
}
|
||||
|
||||
tm parseDate(std::string str) {
|
||||
static tm date;
|
||||
// TODO: Handle exceptions
|
||||
int year = stoi(str.substr(0, 4));
|
||||
int mon = stoi(str.substr(5, 2));
|
||||
int day = stoi(str.substr(8, 2));
|
||||
int hours = stoi(str.substr(11, 2));
|
||||
int min = stoi(str.substr(14, 2));
|
||||
int sec = stoi(str.substr(17, 2));
|
||||
date.tm_year = year;
|
||||
date.tm_mon = mon - 1;
|
||||
date.tm_mday = day;
|
||||
date.tm_hour = hours;
|
||||
date.tm_min = min;
|
||||
date.tm_sec = sec;
|
||||
return date;
|
||||
}
|
||||
|
||||
std::string printDate(tm date) {
|
||||
static char str[25];
|
||||
snprintf(str, 21, "%04d-%02d-%02dT%02d:%02d:%02dZ", date.tm_year,
|
||||
date.tm_mon + 1, date.tm_mday, date.tm_hour, date.tm_min,
|
||||
date.tm_sec);
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string hash(std::string data) {
|
||||
unsigned char bytes[SHA256_DIGEST_LENGTH];
|
||||
SHA256((unsigned char *) &data[0], data.size(), bytes);
|
||||
char hash[(SHA256_DIGEST_LENGTH * 2) + 1];
|
||||
int i;
|
||||
for(i = 0; i < SHA256_DIGEST_LENGTH; i++) {
|
||||
sprintf(hash + (i * 2), "%02x", bytes[i]);
|
||||
}
|
||||
hash[SHA256_DIGEST_LENGTH * 2] = '\0';
|
||||
return std::string(hash, SHA256_DIGEST_LENGTH * 2);
|
||||
}
|
||||
} // namespace util
|
|
@ -6,29 +6,27 @@ set(TEST_SOURCES
|
|||
budget_test.cpp
|
||||
transaction_test.h
|
||||
transaction_test.cpp
|
||||
utils_test.h
|
||||
utils_test.cpp
|
||||
)
|
||||
|
||||
find_library(CPPUNIT cppunit)
|
||||
|
||||
add_executable(twigs_test
|
||||
${TEST_SOURCES}
|
||||
${PUBLIC_HEADERS}
|
||||
)
|
||||
add_executable(twigs_test ${TEST_SOURCES})
|
||||
|
||||
target_link_libraries(twigs_test libtwigs ${CPPUNIT})
|
||||
|
||||
target_include_directories(twigs_test PRIVATE
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${TWIGS_INCLUDE_DIR}>
|
||||
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include/twigs>
|
||||
)
|
||||
|
||||
message("CMAKE_INSTALL_INCLUDEDIR: ${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
message("CMAKE_CURRENT_LIST_DIR}/TWIGS_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR}/${TWIGS_INCLUDE_DIR}")
|
||||
message("PROJECT_BINARY_DIR/include/twigs: ${PROJECT_BINARY_DIR}/include/twigs}")
|
||||
|
||||
set_target_properties(twigs_test PROPERTIES
|
||||
OUTPUT_NAME "twigstest"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION ${PROJECT_VERSION_MAJOR}
|
||||
)
|
||||
|
||||
add_test(NAME twigs_test
|
||||
COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $<TARGET_FILE:twigs_test>
|
||||
)
|
||||
|
||||
add_custom_command(TARGET twigs_test
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $<TARGET_FILE:twigs_test>
|
||||
)
|
||||
|
|
|
@ -1,6 +1,41 @@
|
|||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include "budget_test.h"
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
|
||||
void BudgetTest::parseDate() {
|
||||
Budget budget;
|
||||
void BudgetTest::serialize() {
|
||||
const std::string json =
|
||||
R"({"description":"Monthly expenses","id":"Gbhqm79yC8NereIONtq7W2Mf9MD2y1AU","name":"Monthly Budget"})";
|
||||
Budget b = Budget("Gbhqm79yC8NereIONtq7W2Mf9MD2y1AU", "Monthly Budget",
|
||||
"Monthly expenses");
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Budget serialization failed", json,
|
||||
b.serialize());
|
||||
}
|
||||
|
||||
void BudgetTest::deserialize() {
|
||||
const std::string json =
|
||||
R"({"description":"Monthly expenses","id":"Gbhqm79yC8NereIONtq7W2Mf9MD2y1AU","name":"Monthly Budget"})";
|
||||
Budget b = Budget::deserialize(json);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Budget id parsing failed",
|
||||
std::string("Gbhqm79yC8NereIONtq7W2Mf9MD2y1AU"),
|
||||
b.getId());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Budget name parsing failed",
|
||||
std::string("Monthly Budget"), b.getName());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Budget description parsing failed",
|
||||
std::string("Monthly expenses"),
|
||||
b.getDescription());
|
||||
}
|
||||
|
||||
void BudgetTest::defaultIdsDifferent() {
|
||||
Budget b1;
|
||||
Budget b2;
|
||||
CPPUNIT_ASSERT(b1.getId() != b2.getId());
|
||||
}
|
||||
|
||||
void BudgetTest::hashBudget() {
|
||||
Budget b = Budget("Gbhqm79yC8NereIONtq7W2Mf9MD2y1AU", "Monthly Budget",
|
||||
"Monthly expenses");
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE(
|
||||
"Budget hash failed",
|
||||
std::string(
|
||||
"12fd354740ec016a4b50e2edd1e586107784fe7b88001d8d6ab7ba9ce38aa1d6"),
|
||||
b.hash());
|
||||
}
|
||||
|
|
|
@ -7,10 +7,16 @@
|
|||
|
||||
class BudgetTest: public CppUnit::TestCase {
|
||||
public:
|
||||
void parseDate();
|
||||
void serialize();
|
||||
void deserialize();
|
||||
void defaultIdsDifferent();
|
||||
void hashBudget();
|
||||
|
||||
CPPUNIT_TEST_SUITE( BudgetTest );
|
||||
CPPUNIT_TEST( parseDate );
|
||||
CPPUNIT_TEST( serialize );
|
||||
CPPUNIT_TEST( deserialize );
|
||||
CPPUNIT_TEST( defaultIdsDifferent );
|
||||
CPPUNIT_TEST( hashBudget );
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
};
|
||||
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
#include <cppunit/TextTestRunner.h>
|
||||
#include "budget_test.h"
|
||||
#include "transaction_test.h"
|
||||
#include "utils_test.h"
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION (UtilsTest);
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION (BudgetTest);
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION (TransactionTest);
|
||||
|
||||
int main() {
|
||||
BudgetTest budgetTest;
|
||||
TransactionTest transactionTest;
|
||||
UtilsTest utilsTest;
|
||||
|
||||
CppUnit::Test *test = CppUnit::TestFactoryRegistry::getRegistry().makeTest();
|
||||
CppUnit::TextTestRunner runner;
|
||||
|
|
|
@ -1,9 +1,84 @@
|
|||
#include "transaction_test.h"
|
||||
#include <cppunit/TestCase.h>
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include "transaction_test.h"
|
||||
#include <iostream>
|
||||
#include <time.h>
|
||||
#include <twigs/utils.h>
|
||||
|
||||
void TransactionTest::parseDate() {
|
||||
Transaction transaction;
|
||||
transaction.setDate("2020-01-31T23:59:59Z");
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Transaction date parsing failed", std::string("2020-01-31T23:59:59Z"), transaction.getDate());
|
||||
void TransactionTest::serialize() {
|
||||
const std::string json =
|
||||
R"({"amount":2108,"budgetId":"Gbhqm79yC8NereIONtq7W2Mf9MD2y1AU","categoryId":"Q4R8QLhSksL2wi7XzmrqhL06qm2aZ2S4","createdBy":"1","date":"2021-01-08T13:06:00Z","description":"Books","expense":true,"id":"2snbSS8flrSH6OrvmSEmqyvaduOi2uc2","title":"Amazon"})";
|
||||
|
||||
tm date;
|
||||
date.tm_year = 2021;
|
||||
date.tm_mon = 0;
|
||||
date.tm_mday = 8;
|
||||
date.tm_hour = 13;
|
||||
date.tm_min = 6;
|
||||
date.tm_sec = 0;
|
||||
Transaction t =
|
||||
Transaction("2snbSS8flrSH6OrvmSEmqyvaduOi2uc2", "Amazon", date, "1", 2108,
|
||||
"Books", true, "Q4R8QLhSksL2wi7XzmrqhL06qm2aZ2S4",
|
||||
"Gbhqm79yC8NereIONtq7W2Mf9MD2y1AU");
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Transaction serialization failed", json,
|
||||
t.serialize());
|
||||
}
|
||||
|
||||
void TransactionTest::deserialize() {
|
||||
const std::string json =
|
||||
R"({"id":"2snbSS8flrSH6OrvmSEmqyvaduOi2uc2","title":"Amazon","description":"Books","date":"2021-01-08T13:06:00Z","amount":2108,"expense":true,"budgetId":"Gbhqm79yC8NereIONtq7W2Mf9MD2y1AU","categoryId":"Q4R8QLhSksL2wi7XzmrqhL06qm2aZ2S4","createdBy":"1"})";
|
||||
Transaction t = Transaction::deserialize(json);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Transaction id parsing failed",
|
||||
std::string("2snbSS8flrSH6OrvmSEmqyvaduOi2uc2"),
|
||||
t.getId());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Transaction name parsing failed",
|
||||
std::string("Amazon"), t.getName());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Transaction description parsing failed",
|
||||
std::string("Books"), t.getDescription());
|
||||
tm date = t.getDate();
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Transaction date year parsing failed", 2021,
|
||||
date.tm_year);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Transaction date month parsing failed", 0,
|
||||
date.tm_mon);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Transaction date day parsing failed", 8,
|
||||
date.tm_mday);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Transaction date hour parsing failed", 13,
|
||||
date.tm_hour);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Transaction date min parsing failed", 6,
|
||||
date.tm_min);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Transaction date sec parsing failed", 0,
|
||||
date.tm_sec);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Transaction amount parsing failed", 2108U,
|
||||
t.getAmount());
|
||||
CPPUNIT_ASSERT_MESSAGE("Transaction expense parsing failed", t.isExpense());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Transaction budgetId parsing failed",
|
||||
std::string("Gbhqm79yC8NereIONtq7W2Mf9MD2y1AU"),
|
||||
t.getBudgetId());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Transaction category parsing failed",
|
||||
std::string("Q4R8QLhSksL2wi7XzmrqhL06qm2aZ2S4"),
|
||||
t.getCategoryId());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Transaction createdBy parsing failed",
|
||||
std::string("1"), t.getCreatedBy());
|
||||
}
|
||||
|
||||
void TransactionTest::defaultIdsDifferent() {
|
||||
Transaction t1;
|
||||
Transaction t2;
|
||||
CPPUNIT_ASSERT(t1.getId() != t2.getId());
|
||||
}
|
||||
|
||||
void TransactionTest::hashTransaction() {
|
||||
tm date;
|
||||
date.tm_year = 2021;
|
||||
date.tm_mon = 0;
|
||||
date.tm_mday = 8;
|
||||
date.tm_hour = 13;
|
||||
date.tm_min = 6;
|
||||
date.tm_sec = 0;
|
||||
Transaction t =
|
||||
Transaction("2snbSS8flrSH6OrvmSEmqyvaduOi2uc2", "Amazon", date, "1", 2108,
|
||||
"Books", true, "Q4R8QLhSksL2wi7XzmrqhL06qm2aZ2S4",
|
||||
"Gbhqm79yC8NereIONtq7W2Mf9MD2y1AU");
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Transaction hash failed",
|
||||
std::string("94140eb2923e905360cef1e7aca3d321da39f0608ea17eb944475d81b89a64cb"), t.hash());
|
||||
}
|
||||
|
|
|
@ -7,10 +7,16 @@
|
|||
|
||||
class TransactionTest: public CppUnit::TestCase {
|
||||
public:
|
||||
void parseDate();
|
||||
void serialize();
|
||||
void deserialize();
|
||||
void defaultIdsDifferent();
|
||||
void hashTransaction();
|
||||
|
||||
CPPUNIT_TEST_SUITE( TransactionTest );
|
||||
CPPUNIT_TEST( parseDate );
|
||||
CPPUNIT_TEST( serialize );
|
||||
CPPUNIT_TEST( deserialize );
|
||||
CPPUNIT_TEST( defaultIdsDifferent );
|
||||
CPPUNIT_TEST( hashTransaction );
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
};
|
||||
|
||||
|
|
24
src/test/utils_test.cpp
Normal file
24
src/test/utils_test.cpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
#include "utils_test.h"
|
||||
#include <cppunit/TestCase.h>
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
|
||||
void UtilsTest::parseDateTest() {}
|
||||
|
||||
void UtilsTest::printDateTest() {
|
||||
tm date;
|
||||
date.tm_year = 2020;
|
||||
date.tm_mon = 0;
|
||||
date.tm_mday = 31;
|
||||
date.tm_hour = 23;
|
||||
date.tm_min = 59;
|
||||
date.tm_sec = 59;
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Date printing failed",
|
||||
std::string("2020-01-31T23:59:59Z"),
|
||||
util::printDate(date));
|
||||
}
|
||||
|
||||
void UtilsTest::hashTest() {
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Hashing failed",
|
||||
std::string("9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"),
|
||||
util::hash("test"));
|
||||
}
|
21
src/test/utils_test.h
Normal file
21
src/test/utils_test.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#ifndef UTILS_TEST_H_INCLUDED
|
||||
#define UTILS_TEST_H_INCLUDED
|
||||
|
||||
#include <cppunit/TestCase.h>
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include <twigs/utils.h>
|
||||
|
||||
class UtilsTest: public CppUnit::TestCase {
|
||||
public:
|
||||
void parseDateTest();
|
||||
void printDateTest();
|
||||
void hashTest();
|
||||
|
||||
CPPUNIT_TEST_SUITE( UtilsTest );
|
||||
CPPUNIT_TEST( parseDateTest );
|
||||
CPPUNIT_TEST( printDateTest );
|
||||
CPPUNIT_TEST( hashTest );
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
};
|
||||
|
||||
#endif // UTILS_TEST_H_INCLUDED
|
1
transaction.json
Normal file
1
transaction.json
Normal file
|
@ -0,0 +1 @@
|
|||
{"amount":2108,"budgetId":"Gbhqm79yC8NereIONtq7W2Mf9MD2y1AU","categoryId":"Q4R8QLhSksL2wi7XzmrqhL06qm2aZ2S4","createdBy":"1","date":"2021-01-08T13:06:00Z","description":"Books","expense":true,"id":"2snbSS8flrSH6OrvmSEmqyvaduOi2uc2","title":"Amazon"}
|
Loading…
Reference in a new issue