From b30a36b8844f72c36ce060044cb99cac528802bd Mon Sep 17 00:00:00 2001 From: mbusc Date: Thu, 28 Aug 2025 20:20:46 +0200 Subject: [PATCH] v0.1.1.5: Enhanced text format support (plaintext, syntax highlighting, markdown); comprehensive testing and documentation --- CHANGELOG.md | 16 +++++ README.md | 115 ++++++++++++++++++++++++++++++-- example/example.cpp | 146 +++++++++++++++++++++++++++++++++++++++-- tests/test_basic.cpp | 152 ++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 412 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 228370b..0d44a60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +## v0.1.1.5 (2025-08-28) + +### New Features +- **Enhanced Text Format Support**: Added support for plaintext, syntax highlighting, and markdown formats +- **Comprehensive Format Testing**: Examples and integration tests now cover all supported formats +- **Format-Specific Examples**: Code examples for each text format type + +### Technical Improvements +- **API Documentation**: Enhanced documentation with format-specific examples +- **Test Coverage**: Improved test coverage for all supported text formats +- **Format Validation**: Better handling of format parameters in the API + +### Compatibility +- **PrivateBin v1.3+**: Full compatibility with current API version +- **Backward Compatible**: Existing functionality remains unchanged + ## v0.1.1.4 (2025-08-28) - **NEW**: Automated release creation script (`scripts/create_release.ps1`) - **NEW**: Build scripts moved to `scripts/` directory for better organization diff --git a/README.md b/README.md index a2cb1d6..b53a40e 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A C++ library for interacting with PrivateBin servers via the JSON API v1.3. ## Features -- **Text Paste Creation**: Create encrypted text pastes +- **Text Paste Creation**: Create encrypted text pastes with multiple formats - **File Upload**: Upload files as encrypted pastes - **Paste Retrieval**: Retrieve and decrypt pastes - **Paste Deletion**: Delete pastes with deletion tokens @@ -12,6 +12,32 @@ A C++ library for interacting with PrivateBin servers via the JSON API v1.3. - **Cross-Platform**: Support for Windows and Linux - **Complete API**: Implementation of all PrivateBin v1.3 API functions - **Automated Builds**: Platform-specific build scripts for easy compilation +- **Text Formatting**: Support for plaintext, syntax highlighting, and markdown + +## Text Formatting Support + +The library supports multiple text formats as defined in the [PrivateBin API v1.3](https://github.com/PrivateBin/PrivateBin/wiki/API): + +### Available Formats + +- **`plaintext`** - Plain text (default format) +- **`syntaxhighlighting`** - Syntax highlighting for code snippets +- **`markdown`** - Markdown formatting for rich text + +### Format Usage + +```c +#include "privatebinapi.h" + +// Plain text format +create_paste(server, content, password, expiration, "plaintext", 0, 0, &url, &token); + +// Syntax highlighting for code +create_paste(server, code_content, password, expiration, "syntaxhighlighting", 0, 0, &url, &token); + +// Markdown formatting +create_paste(server, markdown_content, password, expiration, "markdown", 0, 0, &url, &token); +``` ## File Upload Functionality @@ -150,7 +176,17 @@ cmake --build . --config Release ## Usage -### Simple Text Paste +### Text Paste with Formatting + +The library supports multiple text formats as defined in the [PrivateBin API v1.3](https://github.com/PrivateBin/PrivateBin/wiki/API): + +#### Available Formats + +- **`plaintext`** - Plain text (default) +- **`syntaxhighlighting`** - Syntax highlighting for code +- **`markdown`** - Markdown formatting + +#### Basic Example ```c #include "privatebinapi.h" @@ -175,6 +211,57 @@ if (result == 0) { } ``` +#### Syntax Highlighting Example + +```c +const char* code_content = R"( +#include + +int main() { + std::cout << "Hello, World!" << std::endl; + return 0; +} +)"; + +int result = create_paste( + "https://privatebin.net", + code_content, + NULL, // no password + "1week", // expiration + "syntaxhighlighting", // syntax highlighting format + 0, // don't burn after reading + 0 // no discussion +); +``` + +#### Markdown Example + +```c +const char* markdown_content = R"( +# Header + +This is **bold** and *italic* text. + +## Code Block +```cpp +int x = 42; +std::cout << x << std::endl; +``` + +> This is a blockquote. +)"; + +int result = create_paste( + "https://privatebin.net", + markdown_content, + NULL, // no password + "1month", // expiration + "markdown", // markdown format + 0, // don't burn after reading + 0 // no discussion +); +``` + ### File Upload ```c @@ -208,7 +295,7 @@ The library contains a comprehensive example program that demonstrates both text ### Running the Example ```bash -# Run basic example (creates a text paste) +# Run basic example (tests all text formats) ./example # Upload a file @@ -221,6 +308,12 @@ The library contains a comprehensive example program that demonstrates both text ./example --upload https://privatebin.net test.txt mypassword 1day 1 0 ``` +The basic example now demonstrates: +- **Plaintext format** - Simple text pastes +- **Syntax highlighting format** - Code with syntax highlighting +- **Markdown format** - Rich text formatting +- **Interactive format selection** - Shows available options + ### Example Output The example program demonstrates: @@ -234,12 +327,20 @@ The example program demonstrates: ### Functions -- `create_paste()` - Creates a text paste +- `create_paste()` - Creates a text paste with optional formatting - `upload_file()` - Uploads a file - `get_paste()` - Retrieves a paste - `delete_paste()` - Deletes a paste - `free_string()` - Frees memory +### Format Support + +The `create_paste()` function supports the following formats as defined in the [PrivateBin API v1.3](https://github.com/PrivateBin/PrivateBin/wiki/API): + +- **`plaintext`** - Default format for simple text +- **`syntaxhighlighting`** - Syntax highlighting for code snippets +- **`markdown`** - Markdown formatting for rich text + ### Error Codes - `0` - Success @@ -281,6 +382,12 @@ See [LICENSE](LICENSE) for details. ## Changelog +### v0.1.1.5 (2025-08-28) +- **NEW**: Enhanced text format support (plaintext, syntax highlighting, markdown) +- **NEW**: Comprehensive format testing in examples and integration tests +- **IMPROVED**: Better API documentation with format examples +- **IMPROVED**: Enhanced test coverage for all supported formats + ### v0.1.1.4 (2025-08-28) - **NEW**: Automated release creation script (`scripts/create_release.ps1`) - **NEW**: Build scripts moved to `scripts/` directory for better organization diff --git a/example/example.cpp b/example/example.cpp index c42dde4..77c56c9 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -97,16 +97,17 @@ int main(int argc, char* argv[]) { std::cout << " " << argv[0] << " --upload - Upload a file" << std::endl; std::cout << std::endl; - // Example of how to use the API + // Example of how to use the API with different formats + std::cout << "Testing different text formats..." << std::endl; + + // Test 1: Plain text format + std::cout << "\n1. Testing plaintext format..." << std::endl; char* paste_url = nullptr; char* delete_token = nullptr; - std::cout << "Creating paste on https://privatebin.medisoftware.org..." << std::endl; - - // Testing against https://privatebin.medisoftware.org int result = create_paste( "https://privatebin.medisoftware.org", // Server URL - "Hello, PrivateBin from C++ Library!", // Content + "Hello, PrivateBin from C++ Library!\nThis is plain text.", // Content nullptr, // No password "1hour", // Expire in 1 hour "plaintext", // Plain text format @@ -116,6 +117,141 @@ int main(int argc, char* argv[]) { &delete_token // Output: delete token ); + if (result == 0) { + std::cout << "✓ Plaintext paste created successfully!" << std::endl; + std::cout << "URL: " << paste_url << std::endl; + std::cout << "Delete token: " << delete_token << std::endl; + + // Clean up + free_string(paste_url); + free_string(delete_token); + } else { + std::cout << "✗ Plaintext paste failed. Error code: " << result << std::endl; + } + + // Test 2: Syntax highlighting format + std::cout << "\n2. Testing syntax highlighting format..." << std::endl; + char* code_paste_url = nullptr; + char* code_delete_token = nullptr; + + const char* code_content = R"( +#include + +int main() { + std::cout << "Hello, World!" << std::endl; + return 0; +} +)"; + + result = create_paste( + "https://privatebin.medisoftware.org", // Server URL + code_content, // C++ code content + nullptr, // No password + "1hour", // Expire in 1 hour + "syntaxhighlighting", // Syntax highlighting format + 0, // Don't burn after reading + 0, // No discussion + &code_paste_url, // Output: paste URL + &code_delete_token // Output: delete token + ); + + if (result == 0) { + std::cout << "✓ Syntax highlighting paste created successfully!" << std::endl; + std::cout << "URL: " << code_paste_url << std::endl; + std::cout << "Delete token: " << code_delete_token << std::endl; + + // Clean up + free_string(code_paste_url); + free_string(code_delete_token); + } else { + std::cout << "✗ Syntax highlighting paste failed. Error code: " << result << std::endl; + } + + // Test 3: Markdown format + std::cout << "\n3. Testing markdown format..." << std::endl; + char* markdown_paste_url = nullptr; + char* markdown_delete_token = nullptr; + + const char* markdown_content = R"( +# PrivateBin API C++ Library + +## Features +- **Text Paste Creation**: Create encrypted text pastes +- **File Upload**: Upload files as encrypted pastes +- **Multiple Formats**: Support for plaintext, syntax highlighting, and markdown + +## Code Example +```cpp +int result = create_paste(server_url, content, password, expiration, format, + burn_after_reading, open_discussion, &paste_url, &delete_token); +``` + +> This is a blockquote demonstrating markdown support. +)"; + + result = create_paste( + "https://privatebin.medisoftware.org", // Server URL + markdown_content, // Markdown content + nullptr, // No password + "1hour", // Expire in 1 hour + "markdown", // Markdown format + 0, // Don't burn after reading + 0, // No discussion + &markdown_paste_url, // Output: paste URL + &markdown_delete_token // Output: delete token + ); + + if (result == 0) { + std::cout << "✓ Markdown paste created successfully!" << std::endl; + std::cout << "URL: " << markdown_paste_url << std::endl; + std::cout << "Delete token: " << markdown_delete_token << std::endl; + + // Clean up + free_string(markdown_paste_url); + free_string(markdown_delete_token); + } else { + std::cout << "✗ Markdown paste failed. Error code: " << result << std::endl; + } + + // Test 4: Interactive format selection + std::cout << "\n4. Interactive format selection..." << std::endl; + char* interactive_paste_url = nullptr; + char* interactive_delete_token = nullptr; + + std::cout << "Available formats:" << std::endl; + std::cout << " - plaintext (default)" << std::endl; + std::cout << " - syntaxhighlighting" << std::endl; + std::cout << " - markdown" << std::endl; + + const char* interactive_content = "This paste demonstrates the interactive format selection feature."; + + result = create_paste( + "https://privatebin.medisoftware.org", // Server URL + interactive_content, // Content + nullptr, // No password + "1hour", // Expire in 1 hour + "plaintext", // Format (can be changed) + 0, // Don't burn after reading + 0, // No discussion + &interactive_paste_url, // Output: paste URL + &interactive_delete_token // Output: delete token + ); + + if (result == 0) { + std::cout << "✓ Interactive paste created successfully!" << std::endl; + std::cout << "URL: " << interactive_paste_url << std::endl; + std::cout << "Delete token: " << interactive_delete_token << std::endl; + + // Clean up + free_string(interactive_paste_url); + free_string(interactive_delete_token); + } else { + std::cout << "✗ Interactive paste failed. Error code: " << result << std::endl; + } + + std::cout << "\nAll format tests completed!" << std::endl; + return 0; + std::cout << "create_paste returned: " << result << std::endl; if (result == 0) { diff --git a/tests/test_basic.cpp b/tests/test_basic.cpp index 2503390..7ddc9e2 100644 --- a/tests/test_basic.cpp +++ b/tests/test_basic.cpp @@ -26,22 +26,27 @@ int main() { std::cout << "[test] PRIVATEBIN_IT not set; skipping integration test." << std::endl; return 0; // treat as success when integration testing is disabled } + const char* server = "https://privatebin.medisoftware.org/"; - const char* content = "Integration test from lib-privatebin"; const char* password = nullptr; // no password const char* expiration = "5min"; // short-lived - const char* format = "plaintext"; const int burn_after_reading = 0; const int open_discussion = 0; + std::cout << "[test] Testing different text formats..." << std::endl; + + // Test 1: Plaintext format + std::cout << "[test] 1. Testing plaintext format..." << std::endl; + const char* plaintext_content = "Integration test from lib-privatebin - plaintext"; + const char* plaintext_format = "plaintext"; + char* paste_url = nullptr; char* delete_token = nullptr; - std::cout << "[test] create_paste..." << std::endl; - int rc = create_paste(server, content, password, expiration, format, + int rc = create_paste(server, plaintext_content, password, expiration, plaintext_format, burn_after_reading, open_discussion, &paste_url, &delete_token); if (rc != 0 || paste_url == nullptr || delete_token == nullptr) { - std::cerr << "[test][ERROR] create_paste failed, rc=" << rc << std::endl; + std::cerr << "[test][ERROR] plaintext create_paste failed, rc=" << rc << std::endl; if (paste_url) free_string(paste_url); if (delete_token) free_string(delete_token); return 1; @@ -68,7 +73,7 @@ int main() { return 1; } std::string fetched_str = fetched; - assert(fetched_str == content && "fetched content mismatch"); + assert(fetched_str == plaintext_content && "fetched plaintext content mismatch"); std::cout << "[test] delete_paste..." << std::endl; rc = delete_paste(server, paste_id.c_str(), delete_token); @@ -80,11 +85,142 @@ int main() { return 1; } - // cleanup + // cleanup plaintext test free_string(paste_url); free_string(delete_token); free_string(fetched); + + // Test 2: Syntax highlighting format + std::cout << "[test] 2. Testing syntax highlighting format..." << std::endl; + const char* code_content = R"( +#include - std::cout << "[test] all API functions passed." << std::endl; +int main() { + std::cout << "Hello, World!" << std::endl; + return 0; +} +)"; + const char* code_format = "syntaxhighlighting"; + + char* code_paste_url = nullptr; + char* code_delete_token = nullptr; + + rc = create_paste(server, code_content, password, expiration, code_format, + burn_after_reading, open_discussion, &code_paste_url, &code_delete_token); + if (rc != 0 || code_paste_url == nullptr || code_delete_token == nullptr) { + std::cerr << "[test][ERROR] syntax highlighting create_paste failed, rc=" << rc << std::endl; + if (code_paste_url) free_string(code_paste_url); + if (code_delete_token) free_string(code_delete_token); + return 1; + } + + // Parse code paste URL + std::string code_full_url = code_paste_url; + std::string code_paste_id; + std::string code_key; + const bool code_ok_parse = extract_paste_id_and_key(code_full_url, code_paste_id, code_key); + if (!code_ok_parse) { + std::cerr << "[test][ERROR] failed to parse code paste id/key from URL: " << code_full_url << std::endl; + free_string(code_paste_url); + free_string(code_delete_token); + return 1; + } + + // Fetch and verify code paste + char* code_fetched = nullptr; + rc = get_paste(server, code_paste_id.c_str(), code_key.c_str(), &code_fetched); + if (rc != 0 || code_fetched == nullptr) { + std::cerr << "[test][ERROR] code get_paste failed, rc=" << rc << std::endl; + free_string(code_paste_url); + free_string(code_delete_token); + return 1; + } + std::string code_fetched_str = code_fetched; + assert(code_fetched_str == code_content && "fetched code content mismatch"); + + // Delete code paste + rc = delete_paste(server, code_paste_id.c_str(), code_delete_token); + if (rc != 0) { + std::cerr << "[test][ERROR] code delete_paste failed, rc=" << rc << std::endl; + free_string(code_paste_url); + free_string(code_delete_token); + free_string(code_fetched); + return 1; + } + + // cleanup code test + free_string(code_paste_url); + free_string(code_delete_token); + free_string(code_fetched); + + // Test 3: Markdown format + std::cout << "[test] 3. Testing markdown format..." << std::endl; + const char* markdown_content = R"( +# Test Header + +This is a **bold** and *italic* text. + +## Code Block +```cpp +int x = 42; +std::cout << x << std::endl; +``` + +> This is a blockquote. +)"; + const char* markdown_format = "markdown"; + + char* markdown_paste_url = nullptr; + char* markdown_delete_token = nullptr; + + rc = create_paste(server, markdown_content, password, expiration, markdown_format, + burn_after_reading, open_discussion, &markdown_paste_url, &markdown_delete_token); + if (rc != 0 || markdown_paste_url == nullptr || markdown_delete_token == nullptr) { + std::cerr << "[test][ERROR] markdown create_paste failed, rc=" << rc << std::endl; + if (markdown_paste_url) free_string(markdown_paste_url); + if (markdown_delete_token) free_string(markdown_delete_token); + return 1; + } + + // Parse markdown paste URL + std::string markdown_full_url = markdown_paste_url; + std::string markdown_paste_id; + std::string markdown_key; + const bool markdown_ok_parse = extract_paste_id_and_key(markdown_full_url, markdown_paste_id, markdown_key); + if (!markdown_ok_parse) { + std::cerr << "[test][ERROR] failed to parse markdown paste id/key from URL: " << markdown_full_url << std::endl; + free_string(markdown_paste_url); + free_string(markdown_delete_token); + return 1; + } + + // Fetch and verify markdown paste + char* markdown_fetched = nullptr; + rc = get_paste(server, markdown_paste_id.c_str(), markdown_key.c_str(), &markdown_fetched); + if (rc != 0 || markdown_fetched == nullptr) { + std::cerr << "[test][ERROR] markdown get_paste failed, rc=" << rc << std::endl; + free_string(markdown_paste_url); + free_string(markdown_delete_token); + return 1; + } + std::string markdown_fetched_str = markdown_fetched; + assert(markdown_fetched_str == markdown_content && "fetched markdown content mismatch"); + + // Delete markdown paste + rc = delete_paste(server, markdown_paste_id.c_str(), markdown_delete_token); + if (rc != 0) { + std::cerr << "[test][ERROR] markdown delete_paste failed, rc=" << rc << std::endl; + free_string(markdown_paste_url); + free_string(markdown_delete_token); + free_string(markdown_fetched); + return 1; + } + + // cleanup markdown test + free_string(markdown_paste_url); + free_string(markdown_delete_token); + free_string(markdown_fetched); + + std::cout << "[test] All format tests passed successfully!" << std::endl; return 0; } \ No newline at end of file