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
|
||||
CTestTestfile.cmake
|
||||
_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