feat(lib): Initialize libnextcloud C++17 library scaffolding #26
131
shared/CMakeLists.txt
Normal file
131
shared/CMakeLists.txt
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.15)
|
||||||
|
project(libnextcloud VERSION 0.1.0 LANGUAGES CXX)
|
||||||
|
|
||||||
|
# C++17 required
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
|
# Options
|
||||||
|
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
|
||||||
|
option(BUILD_TESTING "Build tests" ON)
|
||||||
|
option(BUILD_EXAMPLES "Build examples" OFF)
|
||||||
|
|
||||||
|
# Library sources (currently empty, will be populated as we implement components)
|
||||||
|
set(NEXTCLOUD_SOURCES
|
||||||
|
# src/webdav_client.cpp # Will be added in future
|
||||||
|
# src/auth.cpp # Will be added in future
|
||||||
|
# src/upload_manager.cpp # Will be added in future
|
||||||
|
# src/folder_manager.cpp # Will be added in future
|
||||||
|
# src/config.cpp # Will be added in future
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create library target
|
||||||
|
# For now, it's header-only (version.hpp and types.hpp)
|
||||||
|
# We'll add sources when we implement components
|
||||||
|
add_library(nextcloud INTERFACE)
|
||||||
|
|
||||||
|
# Include directories
|
||||||
|
target_include_directories(nextcloud
|
||||||
|
INTERFACE
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||||
|
$<INSTALL_INTERFACE:include>
|
||||||
|
)
|
||||||
|
|
||||||
|
# Require C++17 for consumers
|
||||||
|
target_compile_features(nextcloud INTERFACE cxx_std_17)
|
||||||
|
|
||||||
|
# Dependencies (will be uncommented as we add implementation)
|
||||||
|
# find_package(CURL REQUIRED)
|
||||||
|
# find_package(MbedTLS REQUIRED)
|
||||||
|
# find_package(tinyxml2 REQUIRED)
|
||||||
|
|
||||||
|
# Link libraries (commented out until we have actual implementation)
|
||||||
|
# target_link_libraries(nextcloud
|
||||||
|
# PUBLIC
|
||||||
|
# CURL::libcurl
|
||||||
|
# MbedTLS::mbedtls
|
||||||
|
# tinyxml2::tinyxml2
|
||||||
|
# )
|
||||||
|
|
||||||
|
# Compiler warnings
|
||||||
|
if(MSVC)
|
||||||
|
target_compile_options(nextcloud INTERFACE /W4)
|
||||||
|
else()
|
||||||
|
target_compile_options(nextcloud INTERFACE -Wall -Wextra -Wpedantic)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Testing
|
||||||
|
if(BUILD_TESTING)
|
||||||
|
enable_testing()
|
||||||
|
add_subdirectory(tests)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
if(BUILD_EXAMPLES)
|
||||||
|
add_subdirectory(examples)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Install rules
|
||||||
|
install(TARGETS nextcloud
|
||||||
|
EXPORT nextcloudTargets
|
||||||
|
LIBRARY DESTINATION lib
|
||||||
|
ARCHIVE DESTINATION lib
|
||||||
|
RUNTIME DESTINATION bin
|
||||||
|
INCLUDES DESTINATION include
|
||||||
|
)
|
||||||
|
|
||||||
|
install(DIRECTORY include/
|
||||||
|
DESTINATION include
|
||||||
|
FILES_MATCHING PATTERN "*.hpp"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Generate and install CMake config files
|
||||||
|
include(CMakePackageConfigHelpers)
|
||||||
|
|
||||||
|
write_basic_package_version_file(
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/nextcloudConfigVersion.cmake"
|
||||||
|
VERSION ${PROJECT_VERSION}
|
||||||
|
COMPATIBILITY AnyNewerVersion
|
||||||
|
)
|
||||||
|
|
||||||
|
configure_package_config_file(
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/nextcloudConfig.cmake.in"
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/nextcloudConfig.cmake"
|
||||||
|
INSTALL_DESTINATION lib/cmake/nextcloud
|
||||||
|
)
|
||||||
|
|
||||||
|
install(FILES
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/nextcloudConfig.cmake"
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/nextcloudConfigVersion.cmake"
|
||||||
|
DESTINATION lib/cmake/nextcloud
|
||||||
|
)
|
||||||
|
|
||||||
|
install(EXPORT nextcloudTargets
|
||||||
|
FILE nextcloudTargets.cmake
|
||||||
|
NAMESPACE nextcloud::
|
||||||
|
DESTINATION lib/cmake/nextcloud
|
||||||
|
)
|
||||||
|
|
||||||
|
# pkg-config file
|
||||||
|
configure_file(
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/libnextcloud.pc.in"
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/libnextcloud.pc"
|
||||||
|
@ONLY
|
||||||
|
)
|
||||||
|
|
||||||
|
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libnextcloud.pc"
|
||||||
|
DESTINATION lib/pkgconfig
|
||||||
|
)
|
||||||
|
|
||||||
|
# Print configuration summary
|
||||||
|
message(STATUS "")
|
||||||
|
message(STATUS "libnextcloud Configuration Summary:")
|
||||||
|
message(STATUS " Version: ${PROJECT_VERSION}")
|
||||||
|
message(STATUS " Build type: ${CMAKE_BUILD_TYPE}")
|
||||||
|
message(STATUS " C++ standard: C++${CMAKE_CXX_STANDARD}")
|
||||||
|
message(STATUS " Shared libraries: ${BUILD_SHARED_LIBS}")
|
||||||
|
message(STATUS " Build tests: ${BUILD_TESTING}")
|
||||||
|
message(STATUS " Build examples: ${BUILD_EXAMPLES}")
|
||||||
|
message(STATUS " Install prefix: ${CMAKE_INSTALL_PREFIX}")
|
||||||
|
message(STATUS "")
|
||||||
288
shared/README.md
Normal file
288
shared/README.md
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
# libnextcloud
|
||||||
|
|
||||||
|
Cross-platform C++17 library for Nextcloud connectivity on embedded devices and homebrew platforms.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
`libnextcloud` provides a clean, modern C++ API for interacting with Nextcloud servers. It's designed to work on resource-constrained devices like game console homebrew (Nintendo 3DS, Switch, Wii U) while also supporting desktop platforms.
|
||||||
|
|
||||||
|
**Status**: 🚧 In Development - Scaffolding complete, components being implemented
|
||||||
|
|
||||||
|
## Features (Planned)
|
||||||
|
|
||||||
|
- ✅ **Version Management**: Semantic versioning with compile-time and runtime queries
|
||||||
|
- ✅ **Type System**: Comprehensive error codes and data structures
|
||||||
|
- 🚧 **WebDAV Client**: HTTP/HTTPS communication with Nextcloud WebDAV API
|
||||||
|
- 🚧 **Authentication**: Basic Auth (OAuth2 planned)
|
||||||
|
- 🚧 **File Upload**: Streaming uploads with chunking and progress tracking
|
||||||
|
- 🚧 **Folder Management**: List, create, navigate remote folders
|
||||||
|
- 🚧 **Favorites & Recent**: Persistent user preferences
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
### Build Tools
|
||||||
|
- **CMake** 3.15 or later
|
||||||
|
- **C++17 compiler**: GCC 7+, Clang 5+, MSVC 2017+
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
**Required** (when implementation complete):
|
||||||
|
- libcurl 7.68+
|
||||||
|
- mbedTLS 2.16+
|
||||||
|
- tinyxml2 9.0+
|
||||||
|
|
||||||
|
**Testing**:
|
||||||
|
- Google Test 1.11+
|
||||||
|
|
||||||
|
**Header-Only**:
|
||||||
|
- nlohmann/json 3.10+ (for configuration, future)
|
||||||
|
|
||||||
|
### Platform Support
|
||||||
|
|
||||||
|
| Platform | Status | Notes |
|
||||||
|
|----------|--------|-------|
|
||||||
|
| Linux | ✅ Development | Primary development platform |
|
||||||
|
| Nintendo 3DS | ✅ Planned | Via devkitARM in container |
|
||||||
|
| Nintendo Switch | 🔜 Planned | |
|
||||||
|
| Wii U | 🔜 Planned | |
|
||||||
|
| PlayStation Vita | 🔜 Planned | |
|
||||||
|
| Windows | 🔜 Planned | |
|
||||||
|
| macOS | 🔜 Planned | |
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Building
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Configure (modern CMake style)
|
||||||
|
cmake -S . -B build
|
||||||
|
|
||||||
|
# Build
|
||||||
|
cmake --build build
|
||||||
|
|
||||||
|
# Run tests
|
||||||
|
cmake --build build --target test
|
||||||
|
# or with CTest for detailed output:
|
||||||
|
# ctest --test-dir build --output-on-failure
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using in Your Project
|
||||||
|
|
||||||
|
#### CMake
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
find_package(nextcloud REQUIRED)
|
||||||
|
|
||||||
|
add_executable(my_app main.cpp)
|
||||||
|
target_link_libraries(my_app nextcloud::nextcloud)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### pkg-config
|
||||||
|
|
||||||
|
```bash
|
||||||
|
g++ -std=c++17 main.cpp $(pkg-config --cflags --libs libnextcloud)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Basic Usage
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <nextcloud/version.hpp>
|
||||||
|
#include <nextcloud/types.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Get library version
|
||||||
|
std::cout << "libnextcloud v" << nextcloud::getVersionString() << std::endl;
|
||||||
|
|
||||||
|
// Check version compatibility
|
||||||
|
if (nextcloud::isVersionAtLeast(0, 1, 0)) {
|
||||||
|
std::cout << "Version is compatible!" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use error types
|
||||||
|
nextcloud::NextcloudError error = nextcloud::NextcloudError::Success;
|
||||||
|
std::cout << "Status: " << nextcloud::errorToString(error) << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
shared/
|
||||||
|
├── CMakeLists.txt # Build configuration
|
||||||
|
├── README.md # This file
|
||||||
|
├── libnextcloud.pc.in # pkg-config template
|
||||||
|
├── nextcloudConfig.cmake.in # CMake config template
|
||||||
|
├── include/
|
||||||
|
│ └── nextcloud/
|
||||||
|
│ ├── version.hpp # Version information
|
||||||
|
│ ├── types.hpp # Common types and errors
|
||||||
|
│ ├── webdav_client.hpp # (Coming soon)
|
||||||
|
│ ├── auth.hpp # (Coming soon)
|
||||||
|
│ ├── upload_manager.hpp # (Coming soon)
|
||||||
|
│ ├── folder_manager.hpp # (Coming soon)
|
||||||
|
│ └── config.hpp # (Coming soon)
|
||||||
|
├── src/ # Implementation files (future)
|
||||||
|
├── tests/
|
||||||
|
│ ├── CMakeLists.txt
|
||||||
|
│ └── smoke_test.cpp # Basic tests
|
||||||
|
├── examples/ # Usage examples (future)
|
||||||
|
└── docs/ # Documentation (future)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building for Platforms
|
||||||
|
|
||||||
|
### Linux (Development)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir build && cd build
|
||||||
|
cmake ..
|
||||||
|
make
|
||||||
|
make test
|
||||||
|
```
|
||||||
|
|
||||||
|
### Nintendo 3DS (Container)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# From project root
|
||||||
|
podman run --rm -v .:/project:z tomusan/devkitarm-3ds:latest \
|
||||||
|
bash -c "cd /project/shared && mkdir -p build && cd build && cmake .. && make"
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Documentation
|
||||||
|
|
||||||
|
### Version Information
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <nextcloud/version.hpp>
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
nextcloud::VERSION_MAJOR // 0
|
||||||
|
nextcloud::VERSION_MINOR // 1
|
||||||
|
nextcloud::VERSION_PATCH // 0
|
||||||
|
nextcloud::VERSION_STRING // "0.1.0"
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
std::string getVersionString();
|
||||||
|
void getVersion(int& major, int& minor, int& patch);
|
||||||
|
bool isVersionAtLeast(int major, int minor, int patch);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Error Handling
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <nextcloud/types.hpp>
|
||||||
|
|
||||||
|
// Error codes
|
||||||
|
enum class NextcloudError {
|
||||||
|
Success,
|
||||||
|
NetworkError,
|
||||||
|
AuthenticationFailed,
|
||||||
|
ServerError,
|
||||||
|
FileNotFound,
|
||||||
|
// ... more error codes
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert to string
|
||||||
|
const char* errorToString(NextcloudError error);
|
||||||
|
|
||||||
|
// Result type
|
||||||
|
nextcloud::Result<int> result;
|
||||||
|
if (result.isSuccess()) {
|
||||||
|
// Use result.value
|
||||||
|
} else {
|
||||||
|
std::cerr << result.errorMessage() << std::endl;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Data Structures
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Upload progress
|
||||||
|
struct UploadProgress {
|
||||||
|
std::string filename;
|
||||||
|
uint64_t bytesUploaded;
|
||||||
|
uint64_t totalBytes;
|
||||||
|
float percentComplete;
|
||||||
|
float bytesPerSecond;
|
||||||
|
int secondsRemaining;
|
||||||
|
};
|
||||||
|
|
||||||
|
// File information
|
||||||
|
struct FileInfo {
|
||||||
|
std::string name;
|
||||||
|
std::string path;
|
||||||
|
bool isDirectory;
|
||||||
|
uint64_t size;
|
||||||
|
std::time_t modifiedTime;
|
||||||
|
std::string contentType;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Folder information
|
||||||
|
struct FolderInfo {
|
||||||
|
std::string path;
|
||||||
|
std::string displayName;
|
||||||
|
std::time_t lastUsed;
|
||||||
|
bool isFavorite;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run all tests
|
||||||
|
cd build
|
||||||
|
ctest --output-on-failure
|
||||||
|
|
||||||
|
# Or use the custom target
|
||||||
|
make run_tests
|
||||||
|
|
||||||
|
# Run specific test
|
||||||
|
./tests/smoke_test
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development Status
|
||||||
|
|
||||||
|
- ✅ **Phase 1: Scaffolding** - Complete
|
||||||
|
- Directory structure
|
||||||
|
- CMake build system
|
||||||
|
- Version and types headers
|
||||||
|
- Google Test integration
|
||||||
|
- Basic smoke tests
|
||||||
|
|
||||||
|
- 🚧 **Phase 2: WebDAV Client** - Not started
|
||||||
|
- Issue #8
|
||||||
|
|
||||||
|
- 🚧 **Phase 3: Authentication** - Not started
|
||||||
|
- Issue #9
|
||||||
|
|
||||||
|
- 🚧 **Phase 4: Upload Manager** - Not started
|
||||||
|
- Issue #10
|
||||||
|
|
||||||
|
- 🚧 **Phase 5: Folder Management** - Not started
|
||||||
|
- Issue #11
|
||||||
|
|
||||||
|
- 🚧 **Phase 6: Favorites & Recent** - Not started
|
||||||
|
- Issue #12
|
||||||
|
|
||||||
|
- 🚧 **Phase 7: Testing & Docs** - Not started
|
||||||
|
- Issue #13
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
See [CONTRIBUTING.md](../CONTRIBUTING.md) in the project root.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[License TBD - to be determined]
|
||||||
|
|
||||||
|
## Related Documentation
|
||||||
|
|
||||||
|
- [Project Plan](../.plans/CreateLibNextcloud.md)
|
||||||
|
- [Issue #25](https://git.tomusan.com/maj/nextcloud-share/issues/25) - Initialize libnextcloud
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Note**: This library is in active development. The API is subject to change until version 1.0.0.
|
||||||
176
shared/include/nextcloud/types.hpp
Normal file
176
shared/include/nextcloud/types.hpp
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
#ifndef NEXTCLOUD_TYPES_HPP
|
||||||
|
#define NEXTCLOUD_TYPES_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
namespace nextcloud {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Error codes for Nextcloud operations
|
||||||
|
*/
|
||||||
|
enum class NextcloudError {
|
||||||
|
Success = 0,
|
||||||
|
|
||||||
|
// Network errors
|
||||||
|
NetworkError,
|
||||||
|
ConnectionFailed,
|
||||||
|
Timeout,
|
||||||
|
SSLError,
|
||||||
|
|
||||||
|
// Authentication errors
|
||||||
|
AuthenticationFailed,
|
||||||
|
InvalidCredentials,
|
||||||
|
Unauthorized,
|
||||||
|
|
||||||
|
// Server errors
|
||||||
|
ServerError,
|
||||||
|
ServiceUnavailable,
|
||||||
|
InsufficientStorage,
|
||||||
|
|
||||||
|
// File/path errors
|
||||||
|
FileNotFound,
|
||||||
|
PathNotFound,
|
||||||
|
InvalidPath,
|
||||||
|
FileAlreadyExists,
|
||||||
|
PathAlreadyExists,
|
||||||
|
|
||||||
|
// Operation errors
|
||||||
|
OperationFailed,
|
||||||
|
OperationCancelled,
|
||||||
|
InvalidOperation,
|
||||||
|
|
||||||
|
// Parsing/format errors
|
||||||
|
ParseError,
|
||||||
|
InvalidResponse,
|
||||||
|
UnsupportedFormat,
|
||||||
|
|
||||||
|
// Configuration errors
|
||||||
|
InvalidConfiguration,
|
||||||
|
MissingConfiguration,
|
||||||
|
|
||||||
|
// Unknown
|
||||||
|
Unknown
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert error code to human-readable string
|
||||||
|
* @param error The error code
|
||||||
|
* @return String description of the error
|
||||||
|
*/
|
||||||
|
inline const char* errorToString(NextcloudError error) {
|
||||||
|
switch (error) {
|
||||||
|
case NextcloudError::Success: return "Success";
|
||||||
|
case NextcloudError::NetworkError: return "Network error";
|
||||||
|
case NextcloudError::ConnectionFailed: return "Connection failed";
|
||||||
|
case NextcloudError::Timeout: return "Operation timed out";
|
||||||
|
case NextcloudError::SSLError: return "SSL/TLS error";
|
||||||
|
case NextcloudError::AuthenticationFailed: return "Authentication failed";
|
||||||
|
case NextcloudError::InvalidCredentials: return "Invalid credentials";
|
||||||
|
case NextcloudError::Unauthorized: return "Unauthorized";
|
||||||
|
case NextcloudError::ServerError: return "Server error";
|
||||||
|
case NextcloudError::ServiceUnavailable: return "Service unavailable";
|
||||||
|
case NextcloudError::InsufficientStorage: return "Insufficient storage";
|
||||||
|
case NextcloudError::FileNotFound: return "File not found";
|
||||||
|
case NextcloudError::PathNotFound: return "Path not found";
|
||||||
|
case NextcloudError::InvalidPath: return "Invalid path";
|
||||||
|
case NextcloudError::FileAlreadyExists: return "File already exists";
|
||||||
|
case NextcloudError::PathAlreadyExists: return "Path already exists";
|
||||||
|
case NextcloudError::OperationFailed: return "Operation failed";
|
||||||
|
case NextcloudError::OperationCancelled: return "Operation cancelled";
|
||||||
|
case NextcloudError::InvalidOperation: return "Invalid operation";
|
||||||
|
case NextcloudError::ParseError: return "Parse error";
|
||||||
|
case NextcloudError::InvalidResponse: return "Invalid response";
|
||||||
|
case NextcloudError::UnsupportedFormat: return "Unsupported format";
|
||||||
|
case NextcloudError::InvalidConfiguration: return "Invalid configuration";
|
||||||
|
case NextcloudError::MissingConfiguration: return "Missing configuration";
|
||||||
|
case NextcloudError::Unknown: return "Unknown error";
|
||||||
|
default: return "Unrecognized error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Result type for operations that can fail
|
||||||
|
* @tparam T The success value type
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
struct Result {
|
||||||
|
NextcloudError error;
|
||||||
|
T value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if the operation was successful
|
||||||
|
* @return True if no error occurred
|
||||||
|
*/
|
||||||
|
bool isSuccess() const { return error == NextcloudError::Success; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if an error occurred
|
||||||
|
* @return True if an error occurred
|
||||||
|
*/
|
||||||
|
bool isError() const { return error != NextcloudError::Success; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get error message
|
||||||
|
* @return Human-readable error description
|
||||||
|
*/
|
||||||
|
const char* errorMessage() const { return errorToString(error); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Upload progress information
|
||||||
|
*/
|
||||||
|
struct UploadProgress {
|
||||||
|
std::string filename; ///< Name of file being uploaded
|
||||||
|
uint64_t bytesUploaded; ///< Number of bytes uploaded so far
|
||||||
|
uint64_t totalBytes; ///< Total file size in bytes
|
||||||
|
float percentComplete; ///< Completion percentage (0.0 - 100.0)
|
||||||
|
float bytesPerSecond; ///< Current transfer speed
|
||||||
|
int secondsRemaining; ///< Estimated seconds remaining (-1 if unknown)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Information about a file or directory
|
||||||
|
*/
|
||||||
|
struct FileInfo {
|
||||||
|
std::string name; ///< File or directory name
|
||||||
|
std::string path; ///< Full path on server
|
||||||
|
bool isDirectory; ///< True if this is a directory
|
||||||
|
uint64_t size; ///< File size in bytes (0 for directories)
|
||||||
|
std::time_t modifiedTime; ///< Last modification time (Unix timestamp)
|
||||||
|
std::string contentType; ///< MIME type (e.g., "image/png")
|
||||||
|
std::string etag; ///< ETag for change detection
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Information about a favorite or recent folder
|
||||||
|
*/
|
||||||
|
struct FolderInfo {
|
||||||
|
std::string path; ///< Full path on server
|
||||||
|
std::string displayName; ///< User-friendly name
|
||||||
|
std::time_t lastUsed; ///< Last access time (Unix timestamp)
|
||||||
|
bool isFavorite; ///< True if marked as favorite
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief HTTP response information
|
||||||
|
*/
|
||||||
|
struct HttpResponse {
|
||||||
|
int statusCode; ///< HTTP status code (e.g., 200, 404)
|
||||||
|
std::string body; ///< Response body
|
||||||
|
std::string contentType; ///< Content-Type header value
|
||||||
|
NextcloudError error; ///< Error code if request failed
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if response indicates success (2xx status code)
|
||||||
|
* @return True if status code is 200-299
|
||||||
|
*/
|
||||||
|
bool isSuccess() const {
|
||||||
|
return statusCode >= 200 && statusCode < 300 && error == NextcloudError::Success;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace nextcloud
|
||||||
|
|
||||||
|
#endif // NEXTCLOUD_TYPES_HPP
|
||||||
57
shared/include/nextcloud/version.hpp
Normal file
57
shared/include/nextcloud/version.hpp
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#ifndef NEXTCLOUD_VERSION_HPP
|
||||||
|
#define NEXTCLOUD_VERSION_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace nextcloud {
|
||||||
|
|
||||||
|
// Semantic versioning
|
||||||
|
constexpr int VERSION_MAJOR = 0;
|
||||||
|
constexpr int VERSION_MINOR = 1;
|
||||||
|
constexpr int VERSION_PATCH = 0;
|
||||||
|
|
||||||
|
// Build metadata
|
||||||
|
constexpr const char* VERSION_STRING = "0.1.0";
|
||||||
|
constexpr const char* BUILD_DATE = __DATE__;
|
||||||
|
constexpr const char* BUILD_TIME = __TIME__;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the library version as a string
|
||||||
|
* @return Version string in format "MAJOR.MINOR.PATCH"
|
||||||
|
*/
|
||||||
|
inline std::string getVersionString() {
|
||||||
|
return VERSION_STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the library version components
|
||||||
|
* @param major Output parameter for major version
|
||||||
|
* @param minor Output parameter for minor version
|
||||||
|
* @param patch Output parameter for patch version
|
||||||
|
*/
|
||||||
|
inline void getVersion(int& major, int& minor, int& patch) {
|
||||||
|
major = VERSION_MAJOR;
|
||||||
|
minor = VERSION_MINOR;
|
||||||
|
patch = VERSION_PATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if the library version is at least the specified version
|
||||||
|
* @param major Required major version
|
||||||
|
* @param minor Required minor version
|
||||||
|
* @param patch Required patch version
|
||||||
|
* @return True if current version >= required version
|
||||||
|
*/
|
||||||
|
inline bool isVersionAtLeast(int major, int minor, int patch) {
|
||||||
|
if (VERSION_MAJOR > major) return true;
|
||||||
|
if (VERSION_MAJOR < major) return false;
|
||||||
|
|
||||||
|
if (VERSION_MINOR > minor) return true;
|
||||||
|
if (VERSION_MINOR < minor) return false;
|
||||||
|
|
||||||
|
return VERSION_PATCH >= patch;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace nextcloud
|
||||||
|
|
||||||
|
#endif // NEXTCLOUD_VERSION_HPP
|
||||||
11
shared/libnextcloud.pc.in
Normal file
11
shared/libnextcloud.pc.in
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
prefix=@CMAKE_INSTALL_PREFIX@
|
||||||
|
exec_prefix=${prefix}
|
||||||
|
libdir=${exec_prefix}/lib
|
||||||
|
includedir=${prefix}/include
|
||||||
|
|
||||||
|
Name: libnextcloud
|
||||||
|
Description: Cross-platform C++ library for Nextcloud connectivity
|
||||||
|
Version: @PROJECT_VERSION@
|
||||||
|
Requires:
|
||||||
|
Cflags: -I${includedir}
|
||||||
|
Libs: -L${libdir} -lnextcloud
|
||||||
5
shared/nextcloudConfig.cmake.in
Normal file
5
shared/nextcloudConfig.cmake.in
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
@PACKAGE_INIT@
|
||||||
|
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/nextcloudTargets.cmake")
|
||||||
|
|
||||||
|
check_required_components(nextcloud)
|
||||||
30
shared/tests/CMakeLists.txt
Normal file
30
shared/tests/CMakeLists.txt
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.15)
|
||||||
|
|
||||||
|
# Find Google Test
|
||||||
|
find_package(GTest REQUIRED)
|
||||||
|
|
||||||
|
# Include Google Test helpers
|
||||||
|
include(GoogleTest)
|
||||||
|
|
||||||
|
# Test executable
|
||||||
|
add_executable(smoke_test
|
||||||
|
smoke_test.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
# Link against the library and GTest
|
||||||
|
target_link_libraries(smoke_test
|
||||||
|
PRIVATE
|
||||||
|
nextcloud
|
||||||
|
GTest::GTest
|
||||||
|
GTest::Main
|
||||||
|
)
|
||||||
|
|
||||||
|
# Discover and register tests
|
||||||
|
gtest_discover_tests(smoke_test)
|
||||||
|
|
||||||
|
# Add custom target to run tests
|
||||||
|
add_custom_target(run_tests
|
||||||
|
COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
|
||||||
|
DEPENDS smoke_test
|
||||||
|
COMMENT "Running tests..."
|
||||||
|
)
|
||||||
140
shared/tests/smoke_test.cpp
Normal file
140
shared/tests/smoke_test.cpp
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <nextcloud/version.hpp>
|
||||||
|
#include <nextcloud/types.hpp>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file smoke_test.cpp
|
||||||
|
* @brief Basic smoke tests to verify library setup
|
||||||
|
*
|
||||||
|
* These tests ensure that the library headers compile correctly
|
||||||
|
* and basic functionality works as expected.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Test version information
|
||||||
|
TEST(VersionTest, VersionConstants) {
|
||||||
|
EXPECT_EQ(nextcloud::VERSION_MAJOR, 0);
|
||||||
|
EXPECT_EQ(nextcloud::VERSION_MINOR, 1);
|
||||||
|
EXPECT_EQ(nextcloud::VERSION_PATCH, 0);
|
||||||
|
EXPECT_STREQ(nextcloud::VERSION_STRING, "0.1.0");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(VersionTest, GetVersionString) {
|
||||||
|
std::string version = nextcloud::getVersionString();
|
||||||
|
EXPECT_EQ(version, "0.1.0");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(VersionTest, GetVersionComponents) {
|
||||||
|
int major, minor, patch;
|
||||||
|
nextcloud::getVersion(major, minor, patch);
|
||||||
|
EXPECT_EQ(major, 0);
|
||||||
|
EXPECT_EQ(minor, 1);
|
||||||
|
EXPECT_EQ(patch, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(VersionTest, IsVersionAtLeast) {
|
||||||
|
// Current version is 0.1.0
|
||||||
|
EXPECT_TRUE(nextcloud::isVersionAtLeast(0, 0, 0));
|
||||||
|
EXPECT_TRUE(nextcloud::isVersionAtLeast(0, 1, 0));
|
||||||
|
EXPECT_FALSE(nextcloud::isVersionAtLeast(0, 2, 0));
|
||||||
|
EXPECT_FALSE(nextcloud::isVersionAtLeast(1, 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test error types
|
||||||
|
TEST(TypesTest, ErrorToString) {
|
||||||
|
EXPECT_STREQ(nextcloud::errorToString(nextcloud::NextcloudError::Success), "Success");
|
||||||
|
EXPECT_STREQ(nextcloud::errorToString(nextcloud::NextcloudError::NetworkError), "Network error");
|
||||||
|
EXPECT_STREQ(nextcloud::errorToString(nextcloud::NextcloudError::AuthenticationFailed), "Authentication failed");
|
||||||
|
EXPECT_STREQ(nextcloud::errorToString(nextcloud::NextcloudError::FileNotFound), "File not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TypesTest, ResultSuccess) {
|
||||||
|
nextcloud::Result<int> result;
|
||||||
|
result.error = nextcloud::NextcloudError::Success;
|
||||||
|
result.value = 42;
|
||||||
|
|
||||||
|
EXPECT_TRUE(result.isSuccess());
|
||||||
|
EXPECT_FALSE(result.isError());
|
||||||
|
EXPECT_EQ(result.value, 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TypesTest, ResultError) {
|
||||||
|
nextcloud::Result<std::string> result;
|
||||||
|
result.error = nextcloud::NextcloudError::NetworkError;
|
||||||
|
result.value = "";
|
||||||
|
|
||||||
|
EXPECT_FALSE(result.isSuccess());
|
||||||
|
EXPECT_TRUE(result.isError());
|
||||||
|
EXPECT_STREQ(result.errorMessage(), "Network error");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TypesTest, UploadProgressStruct) {
|
||||||
|
nextcloud::UploadProgress progress;
|
||||||
|
progress.filename = "test.txt";
|
||||||
|
progress.bytesUploaded = 50;
|
||||||
|
progress.totalBytes = 100;
|
||||||
|
progress.percentComplete = 50.0f;
|
||||||
|
progress.bytesPerSecond = 1024.0f;
|
||||||
|
progress.secondsRemaining = 1;
|
||||||
|
|
||||||
|
EXPECT_EQ(progress.filename, "test.txt");
|
||||||
|
EXPECT_EQ(progress.bytesUploaded, 50);
|
||||||
|
EXPECT_EQ(progress.totalBytes, 100);
|
||||||
|
EXPECT_FLOAT_EQ(progress.percentComplete, 50.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TypesTest, FileInfoStruct) {
|
||||||
|
nextcloud::FileInfo file;
|
||||||
|
file.name = "document.pdf";
|
||||||
|
file.path = "/Documents/document.pdf";
|
||||||
|
file.isDirectory = false;
|
||||||
|
file.size = 1024;
|
||||||
|
file.modifiedTime = 1234567890;
|
||||||
|
file.contentType = "application/pdf";
|
||||||
|
|
||||||
|
EXPECT_EQ(file.name, "document.pdf");
|
||||||
|
EXPECT_EQ(file.path, "/Documents/document.pdf");
|
||||||
|
EXPECT_FALSE(file.isDirectory);
|
||||||
|
EXPECT_EQ(file.size, 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TypesTest, FolderInfoStruct) {
|
||||||
|
nextcloud::FolderInfo folder;
|
||||||
|
folder.path = "/Photos";
|
||||||
|
folder.displayName = "My Photos";
|
||||||
|
folder.lastUsed = 1234567890;
|
||||||
|
folder.isFavorite = true;
|
||||||
|
|
||||||
|
EXPECT_EQ(folder.path, "/Photos");
|
||||||
|
EXPECT_EQ(folder.displayName, "My Photos");
|
||||||
|
EXPECT_TRUE(folder.isFavorite);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TypesTest, HttpResponseSuccess) {
|
||||||
|
nextcloud::HttpResponse response;
|
||||||
|
response.statusCode = 200;
|
||||||
|
response.body = "OK";
|
||||||
|
response.contentType = "text/plain";
|
||||||
|
response.error = nextcloud::NextcloudError::Success;
|
||||||
|
|
||||||
|
EXPECT_TRUE(response.isSuccess());
|
||||||
|
EXPECT_EQ(response.statusCode, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TypesTest, HttpResponseError) {
|
||||||
|
nextcloud::HttpResponse response;
|
||||||
|
response.statusCode = 404;
|
||||||
|
response.body = "Not Found";
|
||||||
|
response.error = nextcloud::NextcloudError::FileNotFound;
|
||||||
|
|
||||||
|
EXPECT_FALSE(response.isSuccess());
|
||||||
|
EXPECT_EQ(response.statusCode, 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user