12 Jan 2022
|
C++
Google Test
Google Test 샘플 코드입니다.
CMakeLists.txt
FetchContent
명령어를 이용해서 Google Test 라이브러리를 연동합니다.
cmake_minimum_required(VERSION 3.21)
project(gtest_sample)
set(CMAKE_CXX_STANDARD 17)
include(FetchContent)
FetchContent_Declare(googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG release-1.11.0)
FetchContent_MakeAvailable(googletest)
enable_testing()
add_executable(gtest_sample Calculator.cpp CalculatorTests.cpp)
target_link_libraries(
gtest_sample
gtest_main
)
Calculator.hpp
#ifndef GTEST_SAMPLE__CALCULATOR_H_
#define GTEST_SAMPLE__CALCULATOR_H_
class Calculator {
public:
Calculator();
public:
int add(int x, int y);
int sub(int x, int y);
};
#endif //GTEST_SAMPLE__CALCULATOR_H_
Calculator.cpp
#include "Calculator.hpp"
Calculator::Calculator() {
}
int Calculator::add(int x, int y) {
return x + y;
}
int Calculator::sub(int x, int y) {
return x - y;
}
CalculatorTests.cpp
#include <gtest/gtest.h>
#include "Calculator.h"
TEST(Calculator_Add_Test, test_name) {
Calculator c;
EXPECT_EQ(8, c.add(3, 5));
}
TEST(Calculator_Sub_Test, test_name) {
Calculator c;
EXPECT_EQ(7, c.sub(12, 5));
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
실행결과
/Users/snowdeer/Workspace/cpp/gtest/cmake-build-debug/gtest_sample
[==========] Running 2 tests from 2 test suites.
[----------] Global test environment set-up.
[----------] 1 test from Calculator_Add_Test
[ RUN ] Calculator_Add_Test.test_name
[ OK ] Calculator_Add_Test.test_name (0 ms)
[----------] 1 test from Calculator_Add_Test (0 ms total)
[----------] 1 test from Calculator_Sub_Test
[ RUN ] Calculator_Sub_Test.test_name
[ OK ] Calculator_Sub_Test.test_name (0 ms)
[----------] 1 test from Calculator_Sub_Test (0 ms total)
[----------] Global test environment tear-down
[==========] 2 tests from 2 test suites ran. (0 ms total)
[ PASSED ] 2 tests.
Process finished with exit code 0
11 Jan 2022
|
C++
nlohmann json
여기에서 코드 확인할 수 있으며, 샘플이나 설명도 자세하게 되어 있습니다.
그 외에도 JsonCpp나 RapidJSON 등의
라이브러리들도 사용해보았지만, 사용 편의성이 가장 우수한게 nlohmann json
이었던 것 같습니다.
nlohmann json
의 장점은 대략 다음과 같습니다.
- Modern C++ 연산자를 지원. 마치 Python에서의 JSON 사용과 비슷한 느낌을 제공
- 쉬운 사용. 헤더 파일 1개(
nlohmann/json.hpp
)만 include 해서 사용 가능
- 높은 Coverage의 검증 완료
예제 파일
#include <iostream>
#include <string>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
const auto JSON_INDENT = 2;
const std::string strJson = R"(
{
"id" : 123456,
"res" : 111.222,
"name" : "Example Json",
"desc" : "Hello, SnowDeer",
"data" : [
{
"id" : 101,
"name" : "snowdeer"
},
{
"id" : 202,
"name" : "ice-rabbit"
}
],
"info" : {
"notebook" : "macbook m1 pro",
"address" : "Seoul"
}
}
)";
void createJsonObjectTest() {
std::cout << "### Create JSON Object ###" << std::endl;
json obj;
obj["id"] = 0;
obj["data"]["name"] = "snowdeer";
obj["data"]["age"] = 45;
obj["data"]["address"] = "Seoul";
std::cout << obj.dump(JSON_INDENT) << std::endl;
}
void createJsonArrayTest() {
std::cout << "### Create JSON Array ###" << std::endl;
json objs;
objs.push_back("snowdeer");
objs.push_back("ice-rabbit");
objs.push_back("fire-bat");
std::cout << objs.dump(JSON_INDENT) << std::endl;
}
void createMixedJsonObjectTest() {
std::cout << "### Create Mixed JSON Object ###" << std::endl;
json obj1 = {{"id", 1},
{"name", "snowdeer"},
{"age", 45}};
json obj2 = {{"id", 2},
{"name", "ice-rabbit"},
{"age", 32}};
json obj3 = {{"id", 3},
{"name", "fire-bat"},
{"age", 28}};
json objs;
objs.push_back(obj1);
objs.push_back(obj2);
objs.push_back(obj3);
std::cout << objs.dump(JSON_INDENT) << std::endl;
}
void parseJsonTest() {
std::cout << "### parseJson Test ###" << std::endl;
auto j = json::parse(strJson);
std::cout << j.dump(JSON_INDENT) << std::endl;
std::cout << j["data"].dump(JSON_INDENT) << std::endl;
std::cout << j["datxxx"].dump(JSON_INDENT) << std::endl; // 잘못된 Key에 대해서는 null
// std::cout << j["data"]["name"].dump(JSON_INDENT) << std::endl; // 배열을 이런 식으로 접근하면 Exception
std::cout << j["data"][0]["name"].dump(JSON_INDENT) << std::endl;
}
std::string getTypeOfValue(json value) {
if (value.is_array()) return "array";
if (value.is_boolean()) return "boolean";
if (value.is_null()) return "null";
if (value.is_number_integer()) return "integer";
if (value.is_number_float()) return "double";
if (value.is_string()) return "string";
if (value.is_object()) return "object";
return "Unknown";
}
void getKeyValueListTest() {
std::cout << "### Key Value Test ###" << std::endl << std::endl;;
auto j = json::parse(strJson);
for (json::iterator it = j.begin(); it != j.end(); ++it) {
std::cout << "Key : \"" << it.key() << "\"" << std::endl;
std::cout << "Type : " << getTypeOfValue(it.value()) << std::endl;
std::cout << "Value : " << it.value() << std::endl;
std::cout << std::endl;
}
}
void recursive(json j, int space) {
std::string indent = "";
for (auto i = 0; i < space; i++) {
indent = indent + " ";
}
for (json::iterator it = j.begin(); it != j.end(); ++it) {
std::cout << indent << "Key : \"" << it.key() << "\"" << std::endl;
if (it.value().is_array()) {
std::cout << indent << "[" << std::endl;
for (auto item : it.value()) {
recursive(item, space + 2);
}
std::cout << indent << "]" << std::endl;
}
if (it.value().is_object()) {
std::cout << indent << "{" << std::endl;
recursive(j[it.key()], space + 2);
std::cout << indent << "}" << std::endl;
}
}
}
void recursiveParseJsonTest() {
std::cout << "### Recursive parse Json Test ###" << std::endl;
auto j = json::parse(strJson);
recursive(j, 0);
}
int main() {
std::cout << "Hello, World!" << std::endl;
// createJsonObjectTest();
// createJsonArrayTest();
// createMixedJsonObjectTest();
// parseJsonTest();
// getKeyValueListTest();
recursiveParseJsonTest();
return 0;
}
11 Jan 2022
|
C++
FetchContent
FetchContent
는 CMake 3.11
에 새로 추가된 명령어입니다.
대부분의 언어들은 외부 라이브러리들을 사용하기 위해 라이브러리 설치 또는 종속성 추가를 쉽게 할 수 있는
기능을 제공하고 있습니다. 예를 들면, Java의 maven
이나 gradle
, Python의 pip
등입니다. 하지만, C++에는
그런 기능이 없었기 때문에 외부 라이브러리를 사용하기 위해서는 아주 까다로운 설정이 필요했었습니다.
이제 FetchContent
명령어를 통해 CMake에서도 외부 라이브러리들을 쉽게 설치하고 사용할 수 있게 되었습니다.
ExternalProject과 차이
CMake 3.11 버전 이전에도 ExternalProject
명령어를 이용해서 외부 라이브러리를 사용할 수 있었습니다.
하지만, ExternalProject
명령어는 빌드 타임에 외부 라이브러리를 가져오지만, FetchContent
는 CMake 실행 시점에
외부 라이브러리를 가져온다는 점에서 차이가 있습니다.
FetchContent 사용 예제
CMakeLists.txt
파일에 다음 명령어를 이용해서 외부 라이브러리를 가져올 수 있습니다.
여기서는 nlohnmann json를 예시로 작성했습니다.
include(FetchContent)
FetchContent_Declare(json
GIT_REPOSITORY https://github.com/nlohmann/json
GIT_TAG v3.10.5
GIT_PROGRESS TRUE
GIT_SHALLOW TRUE)
FetchContent_MakeAvailable(json)
CMakeLists.txt 전체 코드
cmake_minimum_required(VERSION 3.21)
project(nhlomann_json_example)
set(CMAKE_CXX_STANDARD 14)
include(FetchContent)
FetchContent_Declare(json
GIT_REPOSITORY https://github.com/nlohmann/json
GIT_PROGRESS TRUE
GIT_SHALLOW TRUE
GIT_TAG v3.10.5)
FetchContent_MakeAvailable(json)
add_executable(nhlomann_json_example main.cpp)
target_link_libraries(nhlomann_json_example
PRIVATE nlohmann_json::nlohmann_json)
main.cpp
그 이후에는 아래와 같이 nlohmann/json.hpp
파일 등을 include
해서 사용할 수 있습니다.
#include <iostream>
#include <nlohmann/json.hpp>
int main() {
std::cout << "Hello, World!" << std::endl;
// ...
return 0;
}
10 Jan 2022
|
리눅스
Remote PC (Windows -> Ubuntu)
Windows에서 Ubuntu PC에 원격 접속할 수 있도록 설정하는 방법입니다.
환경은 Windows 10
및 Ubuntu 20.04
입니다.
xrdp 설치
sudo apt update
sudo apt install xrdp
sudo systemctl enable --now xrdp
sudo ufw allow from any to any port 3389 proto tcp
그 이후 Windows의 원격데스크탑 접속
을 이용해서 리눅스에 접속하면 되고,
다이얼로그 창이 뜨면, Xorg
Session, 계정, 패스워드를 입력하면 됩니다.
만약 접속시 Black Screen 만 나오는 경우
/etc/xrdp/startwm.sh
파일을 수정합니다.
sudo gedit /etc/xrdp/startwm.sh
그리고 여기에 아래 내용을 입력합니다.
unset DBUS_SESSION_BUS_ADDRESS
unset XDG_RUNTIME_DIR
. $HOME/.profile
startwm.sh 전체 파일 내용
#!/bin/sh
# xrdp X session start script (c) 2015, 2017 mirabilos
# published under The MirOS Licence
if test -r /etc/profile; then
. /etc/profile
fi
if test -r /etc/default/locale; then
. /etc/default/locale
test -z "${LANG+x}" || export LANG
test -z "${LANGUAGE+x}" || export LANGUAGE
test -z "${LC_ADDRESS+x}" || export LC_ADDRESS
test -z "${LC_ALL+x}" || export LC_ALL
test -z "${LC_COLLATE+x}" || export LC_COLLATE
test -z "${LC_CTYPE+x}" || export LC_CTYPE
test -z "${LC_IDENTIFICATION+x}" || export LC_IDENTIFICATION
test -z "${LC_MEASUREMENT+x}" || export LC_MEASUREMENT
test -z "${LC_MESSAGES+x}" || export LC_MESSAGES
test -z "${LC_MONETARY+x}" || export LC_MONETARY
test -z "${LC_NAME+x}" || export LC_NAME
test -z "${LC_NUMERIC+x}" || export LC_NUMERIC
test -z "${LC_PAPER+x}" || export LC_PAPER
test -z "${LC_TELEPHONE+x}" || export LC_TELEPHONE
test -z "${LC_TIME+x}" || export LC_TIME
test -z "${LOCPATH+x}" || export LOCPATH
fi
unset DBUS_SESSION_BUS_ADDRESS
unset XDG_RUNTIME_DIR
. $HOME/.profile
if test -r /etc/profile; then
. /etc/profile
fi
test -x /etc/X11/Xsession && exec /etc/X11/Xsession
exec /bin/sh /etc/X11/Xsession
02 Jan 2022
|
Flutter
Flutter Dialog
showDialog(
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return AlertDialog(
title: Text(node.name),
content: const Text("Edit node."),
actions: [
TextButton(
child: const Text("Ok"),
onPressed: () {
// TODO
setState(() {
node.name = node.name + '+';
});
Navigator.pop(context);
},
),
],
);
},
);
</pre>