first prototype
This commit is contained in:
parent
daf0fac7a6
commit
1e1f1d32fd
5
.gitignore
vendored
5
.gitignore
vendored
@ -24,4 +24,9 @@ install_manifest.txt
|
|||||||
compile_commands.json
|
compile_commands.json
|
||||||
CTestTestfile.cmake
|
CTestTestfile.cmake
|
||||||
_deps
|
_deps
|
||||||
|
build/
|
||||||
|
|
||||||
|
# ---> Obsidian
|
||||||
|
.obsidian/
|
||||||
|
|
||||||
|
|
||||||
|
58
.vscode/launch.json
vendored
Normal file
58
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "writer",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/build/writer",
|
||||||
|
"args": ["pb1"],
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"cwd": "${workspaceFolder}/build",
|
||||||
|
"environment": [],
|
||||||
|
"externalConsole": false,
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"setupCommands": [
|
||||||
|
{
|
||||||
|
"description": "Enable pretty-printing for gdb",
|
||||||
|
"text": "-enable-pretty-printing",
|
||||||
|
"ignoreFailures": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Set Disassembly Flavor to Intel",
|
||||||
|
"text": "-gdb-set disassembly-flavor intel",
|
||||||
|
"ignoreFailures": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "reader",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/build/reader",
|
||||||
|
"args": ["pb1"],
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"cwd": "${workspaceFolder}/build",
|
||||||
|
"environment": [],
|
||||||
|
"externalConsole": false,
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"setupCommands": [
|
||||||
|
{
|
||||||
|
"description": "Enable pretty-printing for gdb",
|
||||||
|
"text": "-enable-pretty-printing",
|
||||||
|
"ignoreFailures": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Set Disassembly Flavor to Intel",
|
||||||
|
"text": "-gdb-set disassembly-flavor intel",
|
||||||
|
"ignoreFailures": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
33
CMakeLists.txt
Normal file
33
CMakeLists.txt
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.18)
|
||||||
|
|
||||||
|
set(CMAKE_TOOLCHAIN_FILE "/opt/vcpkg/scripts/buildsystems/vcpkg.cmake"
|
||||||
|
CACHE STRING "Vcpkg toolchain file")
|
||||||
|
|
||||||
|
project(protobook LANGUAGES CXX VERSION 0.0.1)
|
||||||
|
|
||||||
|
|
||||||
|
find_package(Catch2 REQUIRED)
|
||||||
|
# Disable automatic CMake build targets like: ContinuousBuild, Experimental, etc..
|
||||||
|
# https://stackoverflow.com/questions/56089330/cmake-creates-lots-of-targets-i-didnt-specify
|
||||||
|
set_property(GLOBAL PROPERTY CTEST_TARGETS_ADDED 1)
|
||||||
|
include(CTest)
|
||||||
|
include(Catch)
|
||||||
|
|
||||||
|
#add_subdirectory(testing)
|
||||||
|
add_subdirectory(addressbook)
|
||||||
|
|
||||||
|
add_executable(writer
|
||||||
|
writer.cpp
|
||||||
|
)
|
||||||
|
target_link_libraries(writer
|
||||||
|
PRIVATE
|
||||||
|
addressbook
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(reader
|
||||||
|
reader.cpp
|
||||||
|
)
|
||||||
|
target_link_libraries(reader
|
||||||
|
PRIVATE
|
||||||
|
addressbook
|
||||||
|
)
|
26
LICENSE
Normal file
26
LICENSE
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
MIT NON-AI License
|
||||||
|
|
||||||
|
Copyright (c) 2024, Andriy Djmil
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of the software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions.
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
In addition, the following restrictions apply:
|
||||||
|
|
||||||
|
1. The Software and any modifications made to it may not be used for the purpose of training or improving machine learning algorithms,
|
||||||
|
including but not limited to artificial intelligence, natural language processing, or data mining. This condition applies to any derivatives,
|
||||||
|
modifications, or updates based on the Software code. Any usage of the Software in an AI-training dataset is considered a breach of this License.
|
||||||
|
|
||||||
|
2. The Software may not be included in any dataset used for training or improving machine learning algorithms,
|
||||||
|
including but not limited to artificial intelligence, natural language processing, or data mining.
|
||||||
|
|
||||||
|
3. Any person or organization found to be in violation of these restrictions will be subject to legal action and may be held liable
|
||||||
|
for any damages resulting from such use.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||||
|
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||||
|
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
README.md
23
README.md
@ -1,3 +1,22 @@
|
|||||||
# denv-cpp
|
Template for C++ based projects
|
||||||
|
- environment: **Docker** container
|
||||||
|
- IDE: **VsCode**
|
||||||
|
- build system: **CMake**
|
||||||
|
- 3rd party libraries: **vcpkg**
|
||||||
|
- testing: **Catch2**
|
||||||
|
|
||||||
C++ project template
|
# Development Environment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./denv/build.sh # create denv image
|
||||||
|
./denv/run-vsc.sh # run container & attach VsCode instance to it
|
||||||
|
```
|
||||||
|
# CMake and CTests
|
||||||
|
|
||||||
|
CTest integration within VsCode is limited - it does not provide link between test case source and test shown in *TestExplorer* view.
|
||||||
|
|
||||||
|
**Solution**
|
||||||
|
1. Disable (CMake > CTest: `Test Explorer Integration` Enabled)
|
||||||
|
2. Install *TestMate* extension
|
||||||
|
It scans the build tree for xxx_test binaries and has neat integration with Catch2.
|
||||||
|
3. You need to enable `rebuild on save` in order for tests in *TestExplorer* to automatically reflect changes in the code. If none - use F7 to rebuild project.
|
37
addressbook/CMakeLists.txt
Normal file
37
addressbook/CMakeLists.txt
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
project(addressbook LANGUAGES CXX VERSION 0.0.1)
|
||||||
|
|
||||||
|
# https://cmake.org/cmake/help/latest/module/FindProtobuf.html
|
||||||
|
find_package(Protobuf REQUIRED)
|
||||||
|
include_directories(${Protobuf_INCLUDE_DIRS})
|
||||||
|
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS addressbook.proto)
|
||||||
|
|
||||||
|
add_library(${PROJECT_NAME}
|
||||||
|
${PROTO_SRCS}
|
||||||
|
#${PROTO_HDRS}
|
||||||
|
)
|
||||||
|
target_link_libraries(${PROJECT_NAME}
|
||||||
|
PRIVATE # private implementation, others can not link with this library
|
||||||
|
protobuf::libprotobuf
|
||||||
|
)
|
||||||
|
target_include_directories(${PROJECT_NAME}
|
||||||
|
PUBLIC # Will make these headers availvable to the library itself
|
||||||
|
# and to any target trying to link agains it
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
#if(testing_enabled)
|
||||||
|
# https://cmake.org/cmake/help/book/mastering-cmake/chapter/Testing%20With%20CMake%20and%20CTest.html
|
||||||
|
add_executable(${PROJECT_NAME}-test
|
||||||
|
test.cpp
|
||||||
|
)
|
||||||
|
target_link_libraries(${PROJECT_NAME}-test PRIVATE Catch2::Catch2WithMain)
|
||||||
|
catch_discover_tests(${PROJECT_NAME}-test)
|
||||||
|
|
||||||
|
add_test(
|
||||||
|
NAME "Custom-test-script"
|
||||||
|
#CONFIGURATIONS "systemt"
|
||||||
|
#COMMAND $<TARGET-FILE>:ctest --success
|
||||||
|
COMMAND echo "testing [OK]"
|
||||||
|
)
|
||||||
|
#endif()
|
27
addressbook/addressbook.proto
Normal file
27
addressbook/addressbook.proto
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
package tutorial;
|
||||||
|
|
||||||
|
message Person {
|
||||||
|
optional string name = 1;
|
||||||
|
optional int32 id = 2;
|
||||||
|
optional string email = 3;
|
||||||
|
|
||||||
|
enum PhoneType {
|
||||||
|
PHONE_TYPE_UNSPECIFIED = 0;
|
||||||
|
PHONE_TYPE_MOBILE = 1;
|
||||||
|
PHONE_TYPE_HOME = 2;
|
||||||
|
PHONE_TYPE_WORK = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message PhoneNumber {
|
||||||
|
optional string number = 1;
|
||||||
|
optional PhoneType type = 2 [default = PHONE_TYPE_HOME];
|
||||||
|
}
|
||||||
|
|
||||||
|
repeated PhoneNumber phones = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AddressBook {
|
||||||
|
repeated Person people = 1;
|
||||||
|
}
|
31
addressbook/test.cpp
Normal file
31
addressbook/test.cpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
|
static int Factorial( int number ) {
|
||||||
|
return number <= 1 ? number : Factorial( number - 1 ) * number; // fail
|
||||||
|
// return number <= 1 ? 1 : Factorial( number - 1 ) * number; // pass
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "Factorial of 0 is 1 (fail)", "[single-file]" ) {
|
||||||
|
REQUIRE( Factorial(0) == 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "Factorials of 1 and higher are computed (pass)", "[single-file]" ) {
|
||||||
|
REQUIRE( Factorial(1) == 1 );
|
||||||
|
REQUIRE( Factorial(2) == 2 );
|
||||||
|
REQUIRE( Factorial(3) == 6 );
|
||||||
|
REQUIRE( Factorial(10) == 3628800 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile & run:
|
||||||
|
// - g++ -std=c++14 -Wall -I$(CATCH_SINGLE_INCLUDE) -o 010-TestCase 010-TestCase.cpp && 010-TestCase --success
|
||||||
|
// - cl -EHsc -I%CATCH_SINGLE_INCLUDE% 010-TestCase.cpp && 010-TestCase --success
|
||||||
|
|
||||||
|
// Expected compact output (all assertions):
|
||||||
|
//
|
||||||
|
// prompt> 010-TestCase --reporter compact --success
|
||||||
|
// 010-TestCase.cpp:14: failed: Factorial(0) == 1 for: 0 == 1
|
||||||
|
// 010-TestCase.cpp:18: passed: Factorial(1) == 1 for: 1 == 1
|
||||||
|
// 010-TestCase.cpp:19: passed: Factorial(2) == 2 for: 2 == 2
|
||||||
|
// 010-TestCase.cpp:20: passed: Factorial(3) == 6 for: 6 == 6
|
||||||
|
// 010-TestCase.cpp:21: passed: Factorial(10) == 3628800 for: 3628800 (0x375f00) == 3628800 (0x375f00)
|
||||||
|
// Failed 1 test case, failed 1 assertion.
|
22
denv/Dockerfile
Normal file
22
denv/Dockerfile
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
FROM debian:bullseye-slim
|
||||||
|
|
||||||
|
RUN apt update \
|
||||||
|
&& apt install -y --no-install-recommends \
|
||||||
|
curl ca-certificates \
|
||||||
|
tar zip unzip pkg-config \
|
||||||
|
git build-essential \
|
||||||
|
gdb cmake
|
||||||
|
|
||||||
|
RUN git clone --depth 1 --branch 2024.04.26 https://github.com/Microsoft/vcpkg.git /opt/vcpkg \
|
||||||
|
&& cd /opt/vcpkg \
|
||||||
|
&& ./bootstrap-vcpkg.sh \
|
||||||
|
&& ./vcpkg integrate install \
|
||||||
|
&& ./vcpkg install catch2
|
||||||
|
|
||||||
|
RUN apt install -y --no-install-recommends \
|
||||||
|
protobuf-compiler libprotobuf-dev \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
|
&& mkdir /denv-template
|
||||||
|
|
||||||
|
WORKDIR /denv-template
|
||||||
|
|
4
denv/build.sh
Executable file
4
denv/build.sh
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euxo pipefail
|
||||||
|
|
||||||
|
docker build --tag denv-template .
|
17
denv/run-vsc.sh
Executable file
17
denv/run-vsc.sh
Executable file
@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
PROJECT_NAME=denv-template
|
||||||
|
|
||||||
|
docker run \
|
||||||
|
--volume $(pwd)/..:/$PROJECT_NAME \
|
||||||
|
--tty \
|
||||||
|
--detach \
|
||||||
|
--name vsc-$PROJECT_NAME \
|
||||||
|
$PROJECT_NAME
|
||||||
|
|
||||||
|
YLW='\033[1;33m'
|
||||||
|
BLU='\033[1;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
echo -e "${YLW}Now launch ${BLU}VsCode${YLW}, attach it to the ${BLU}vsc-${PROJECT_NAME}${YLW} Docker container and open ${BLU}/$PROJECT_NAME${YLW} folder as a worksapce${NC}"
|
66
reader.cpp
Normal file
66
reader.cpp
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
#include "addressbook.pb.h"
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
// Iterates though all people in the AddressBook and prints info about them.
|
||||||
|
void ListPeople(const tutorial::AddressBook& address_book) {
|
||||||
|
for (int i = 0; i < address_book.people_size(); i++) {
|
||||||
|
const tutorial::Person& person = address_book.people(i);
|
||||||
|
|
||||||
|
cout << "Person ID: " << person.id() << endl;
|
||||||
|
cout << " Name: " << person.name() << endl;
|
||||||
|
if (person.has_email()) {
|
||||||
|
cout << " E-mail address: " << person.email() << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < person.phones_size(); j++) {
|
||||||
|
const tutorial::Person::PhoneNumber& phone_number = person.phones(j);
|
||||||
|
|
||||||
|
switch (phone_number.type()) {
|
||||||
|
case tutorial::Person::PHONE_TYPE_MOBILE:
|
||||||
|
cout << " Mobile phone #: ";
|
||||||
|
break;
|
||||||
|
case tutorial::Person::PHONE_TYPE_HOME:
|
||||||
|
cout << " Home phone #: ";
|
||||||
|
break;
|
||||||
|
case tutorial::Person::PHONE_TYPE_WORK:
|
||||||
|
cout << " Work phone #: ";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cout << phone_number.number() << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main function: Reads the entire address book from a file and prints all
|
||||||
|
// the information inside.
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
// Verify that the version of the library that we linked against is
|
||||||
|
// compatible with the version of the headers we compiled against.
|
||||||
|
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tutorial::AddressBook address_book;
|
||||||
|
|
||||||
|
{
|
||||||
|
// Read the existing address book.
|
||||||
|
fstream input(argv[1], ios::in | ios::binary);
|
||||||
|
if (!address_book.ParseFromIstream(&input)) {
|
||||||
|
cerr << "Failed to parse address book." << endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ListPeople(address_book);
|
||||||
|
|
||||||
|
// Optional: Delete all global objects allocated by libprotobuf.
|
||||||
|
google::protobuf::ShutdownProtobufLibrary();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
93
writer.cpp
Normal file
93
writer.cpp
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
#include "addressbook.pb.h"
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
// This function fills in a Person message based on user input.
|
||||||
|
void PromptForAddress(tutorial::Person* person) {
|
||||||
|
cout << "Enter person ID number: ";
|
||||||
|
int id;
|
||||||
|
cin >> id;
|
||||||
|
person->set_id(id);
|
||||||
|
cin.ignore(256, '\n');
|
||||||
|
|
||||||
|
cout << "Enter name: ";
|
||||||
|
getline(cin, *person->mutable_name());
|
||||||
|
|
||||||
|
cout << "Enter email address (blank for none): ";
|
||||||
|
string email;
|
||||||
|
getline(cin, email);
|
||||||
|
if (!email.empty()) {
|
||||||
|
person->set_email(email);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
cout << "Enter a phone number (or leave blank to finish): ";
|
||||||
|
string number;
|
||||||
|
getline(cin, number);
|
||||||
|
if (number.empty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tutorial::Person::PhoneNumber* phone_number = person->add_phones();
|
||||||
|
phone_number->set_number(number);
|
||||||
|
|
||||||
|
cout << "Is this a mobile, home, or work phone? ";
|
||||||
|
string type;
|
||||||
|
getline(cin, type);
|
||||||
|
if (type == "mobile") {
|
||||||
|
phone_number->set_type(tutorial::Person::PHONE_TYPE_MOBILE);
|
||||||
|
} else if (type == "home") {
|
||||||
|
phone_number->set_type(tutorial::Person::PHONE_TYPE_HOME);
|
||||||
|
} else if (type == "work") {
|
||||||
|
phone_number->set_type(tutorial::Person::PHONE_TYPE_WORK);
|
||||||
|
} else {
|
||||||
|
cout << "Unknown phone type. Using default." << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main function: Reads the entire address book from a file,
|
||||||
|
// adds one person based on user input, then writes it back out to the same
|
||||||
|
// file.
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
// Verify that the version of the library that we linked against is
|
||||||
|
// compatible with the version of the headers we compiled against.
|
||||||
|
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tutorial::AddressBook address_book;
|
||||||
|
|
||||||
|
{
|
||||||
|
// Read the existing address book.
|
||||||
|
fstream input(argv[1], ios::in | ios::binary);
|
||||||
|
if (!input) {
|
||||||
|
cout << argv[1] << ": File not found. Creating a new file." << endl;
|
||||||
|
} else if (!address_book.ParseFromIstream(&input)) {
|
||||||
|
cerr << "Failed to parse address book." << endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add an address.
|
||||||
|
PromptForAddress(address_book.add_people());
|
||||||
|
|
||||||
|
{
|
||||||
|
// Write the new address book back to disk.
|
||||||
|
fstream output(argv[1], ios::out | ios::trunc | ios::binary);
|
||||||
|
if (!address_book.SerializeToOstream(&output)) {
|
||||||
|
cerr << "Failed to write address book." << endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional: Delete all global objects allocated by libprotobuf.
|
||||||
|
google::protobuf::ShutdownProtobufLibrary();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user