From 1f786a83ced1594d1dc080986067e51e6ffdfd6c Mon Sep 17 00:00:00 2001 From: Alexander Domene Date: Mon, 25 Aug 2025 20:37:14 +0200 Subject: [PATCH] Initial commit: Create comprehensive Git playground MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Multi-language source code (Python, JavaScript, Java, C++, Go) - Configuration files (JSON, YAML, INI) - Sample data files (CSV, JSON, logs) - Binary and media assets (PNG, SVG, PDF) - Test files and deployment scripts - Nested directory structure for testing Git features 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .gitignore | 81 ++++++++++++++++++++ CLAUDE.MD | 0 README.md | Bin 0 -> 789 bytes assets/binary_data.bin | Bin 0 -> 5120 bytes assets/document.pdf | 36 +++++++++ assets/logo.svg | 17 +++++ assets/sample.png | Bin 0 -> 70 bytes config.json | 19 +++++ config/database.yml | 40 ++++++++++ config/settings.ini | 32 ++++++++ data/logs.txt | 20 +++++ data/sample_data.json | 61 +++++++++++++++ data/users.csv | 11 +++ main.py | 29 +++++++ package.json | 38 +++++++++ scripts/deploy.sh | 71 +++++++++++++++++ src/StringHelper.java | 74 ++++++++++++++++++ src/calculator.js | 46 +++++++++++ src/data_structures.go | 140 ++++++++++++++++++++++++++++++++++ src/math_ops.cpp | 81 ++++++++++++++++++++ src/utils.py | 54 +++++++++++++ tests/unit/test_calculator.js | 53 +++++++++++++ tests/unit/test_utils.py | 101 ++++++++++++++++++++++++ 23 files changed, 1004 insertions(+) create mode 100644 .gitignore create mode 100644 CLAUDE.MD create mode 100644 README.md create mode 100644 assets/binary_data.bin create mode 100644 assets/document.pdf create mode 100644 assets/logo.svg create mode 100644 assets/sample.png create mode 100644 config.json create mode 100644 config/database.yml create mode 100644 config/settings.ini create mode 100644 data/logs.txt create mode 100644 data/sample_data.json create mode 100644 data/users.csv create mode 100644 main.py create mode 100644 package.json create mode 100755 scripts/deploy.sh create mode 100644 src/StringHelper.java create mode 100644 src/calculator.js create mode 100644 src/data_structures.go create mode 100644 src/math_ops.cpp create mode 100644 src/utils.py create mode 100644 tests/unit/test_calculator.js create mode 100644 tests/unit/test_utils.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ba285d5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,81 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +env/ +venv/ +.venv/ +pip-log.txt +pip-delete-this-directory.txt +.tox/ +.coverage +.pytest_cache/ + +# Node.js +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.npm +.eslintcache + +# Java +*.class +*.jar +*.war +*.ear +*.logs +target/ + +# C/C++ +*.o +*.a +*.so +*.exe + +# Go +*.exe~ +*.dlv +*.test +*.out +go.work + +# IDEs +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Logs +logs/ +*.log + +# Environment variables +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# Build directories +build/ +dist/ +out/ + +# Temporary files +tmp/ +temp/ +*.tmp +*.temp \ No newline at end of file diff --git a/CLAUDE.MD b/CLAUDE.MD new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..5dd07efc585b49b809fda6109ea2c884c4e71159 GIT binary patch literal 789 zcmZuvyN=v247^%($`l0LB)~oTbh!j~Re}KC4_K~5+sewKAxgR1zYisQy(!|tu%#h6 zoS6=KjPAtm@GJ3eve}rg@ai)x0WV|X5*-YjAd_StNBD!ubCCua2y;m!pdH|i(|HK| zCXdE+9lUIJ#yr4}60&~?7{`JmfpAHdz_KHtcbu0%qNr~i2S1jC*>i-!ucyyGV!E_n zm~>815(@sQbjX48Nhz}eB&T8<8@+u_80`czMx8fP%vbuA3?=1Yby)B=gILl5o~5yV zrQEjcGbZhC%<*_Up-g7EQ!vH$?t_Pc5^&Uki%Z}(^ldzgJlk->XhuVwn4cU6JEmg2) z!oKEVGr#8IX6#||0?V2j&`(F=$EdDkZhC*IPM~-Tqt@|4tF;23(7AhEc%FT}ho#6= z-ywY7t*c2}`KEC-yr!cWrg`H~YDN_OqA7u#(4Maq%7D{a(wEcBu4s;0FDa*-s70;r TF)^QO><&2A5ebJF7!&{i0RR91 literal 0 HcmV?d00001 diff --git a/assets/document.pdf b/assets/document.pdf new file mode 100644 index 0000000..7569f0b --- /dev/null +++ b/assets/document.pdf @@ -0,0 +1,36 @@ +%PDF-1.4 +1 0 obj +<< /Type /Catalog /Pages 2 0 R >> +endobj +2 0 obj +<< /Type /Pages /Kids [3 0 R] /Count 1 >> +endobj +3 0 obj +<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Resources << /Font << /F1 4 0 R >> >> /Contents 5 0 R >> +endobj +4 0 obj +<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> +endobj +5 0 obj +<< /Length 44 >> +stream +BT +/F1 12 Tf +72 720 Td +(Sample PDF Document) Tj +ET +endstream +endobj +xref +0 6 +0000000000 65535 f +0000000009 00000 n +0000000058 00000 n +0000000115 00000 n +0000000251 00000 n +0000000314 00000 n +trailer +<< /Size 6 /Root 1 0 R >> +startxref +408 +%%EOF \ No newline at end of file diff --git a/assets/logo.svg b/assets/logo.svg new file mode 100644 index 0000000..b58b433 --- /dev/null +++ b/assets/logo.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + LOGO + + + + \ No newline at end of file diff --git a/assets/sample.png b/assets/sample.png new file mode 100644 index 0000000000000000000000000000000000000000..0f2de3749df299a6b84bf6ff1a0b393a1c1fd22b GIT binary patch literal 70 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx1|;Q0k92}1TpU9xZYBTuKYyVd1A7xwz3mB) Q_dp2-Pgg&ebxsLQ0NDZ% + password: <%= ENV['DB_PASSWORD'] %> + host: <%= ENV['DB_HOST'] %> + port: 5432 + +production: + adapter: postgresql + encoding: unicode + database: sandbox_production + pool: 20 + username: <%= ENV['DB_USERNAME'] %> + password: <%= ENV['DB_PASSWORD'] %> + host: <%= ENV['DB_HOST'] %> + port: 5432 + ssl: true \ No newline at end of file diff --git a/config/settings.ini b/config/settings.ini new file mode 100644 index 0000000..db6f572 --- /dev/null +++ b/config/settings.ini @@ -0,0 +1,32 @@ +[DEFAULT] +debug = true +log_level = INFO +max_workers = 4 + +[database] +host = localhost +port = 5432 +name = sandbox_db +timeout = 30 + +[api] +base_url = https://api.example.com +timeout = 10 +retry_count = 3 +rate_limit = 100 + +[cache] +enabled = true +ttl = 3600 +max_size = 1000 + +[logging] +format = %(asctime)s - %(name)s - %(levelname)s - %(message)s +file = logs/application.log +max_file_size = 10MB +backup_count = 5 + +[features] +feature_a = enabled +feature_b = disabled +feature_c = beta \ No newline at end of file diff --git a/data/logs.txt b/data/logs.txt new file mode 100644 index 0000000..d97068f --- /dev/null +++ b/data/logs.txt @@ -0,0 +1,20 @@ +2023-01-25 10:30:15 INFO Application started successfully +2023-01-25 10:30:16 INFO Database connection established +2023-01-25 10:30:17 INFO Loading configuration from config.json +2023-01-25 10:31:22 DEBUG User authentication request for user_id: 12345 +2023-01-25 10:31:23 INFO User 12345 authenticated successfully +2023-01-25 10:32:45 WARN Rate limit approaching for API endpoint /api/users +2023-01-25 10:33:01 ERROR Failed to connect to external service: timeout after 30s +2023-01-25 10:33:02 INFO Retrying connection to external service (attempt 1/3) +2023-01-25 10:33:15 INFO Connection to external service restored +2023-01-25 10:34:28 DEBUG Processing data batch: 500 records +2023-01-25 10:34:35 INFO Data batch processed successfully +2023-01-25 10:35:12 WARN High memory usage detected: 85% +2023-01-25 10:36:45 INFO Garbage collection completed, memory usage: 62% +2023-01-25 10:37:22 DEBUG Cache hit ratio: 92% +2023-01-25 10:38:01 ERROR Database query timeout: SELECT * FROM large_table +2023-01-25 10:38:02 INFO Query optimization applied +2023-01-25 10:38:15 INFO Optimized query completed in 2.3s +2023-01-25 10:39:33 INFO Scheduled task 'data_cleanup' started +2023-01-25 10:40:45 INFO Scheduled task 'data_cleanup' completed +2023-01-25 10:41:00 INFO System health check: All services running normally \ No newline at end of file diff --git a/data/sample_data.json b/data/sample_data.json new file mode 100644 index 0000000..3ab611d --- /dev/null +++ b/data/sample_data.json @@ -0,0 +1,61 @@ +{ + "users": [ + { + "id": 1, + "name": "John Doe", + "profile": { + "age": 28, + "email": "john@example.com", + "preferences": { + "theme": "dark", + "notifications": true, + "language": "en" + } + }, + "posts": [ + { + "id": 101, + "title": "Hello World", + "content": "This is my first post!", + "tags": ["intro", "hello"], + "created_at": "2023-01-15T10:30:00Z" + }, + { + "id": 102, + "title": "Learning Git", + "content": "Git is a powerful version control system.", + "tags": ["git", "learning", "development"], + "created_at": "2023-01-20T14:45:00Z" + } + ] + }, + { + "id": 2, + "name": "Jane Smith", + "profile": { + "age": 32, + "email": "jane@example.com", + "preferences": { + "theme": "light", + "notifications": false, + "language": "es" + } + }, + "posts": [ + { + "id": 103, + "title": "Data Analysis Tips", + "content": "Here are some useful tips for data analysis...", + "tags": ["data", "analysis", "tips"], + "created_at": "2023-01-18T09:15:00Z" + } + ] + } + ], + "metadata": { + "version": "1.0", + "generated_at": "2023-01-25T12:00:00Z", + "total_users": 2, + "total_posts": 3 + } +} \ No newline at end of file diff --git a/data/users.csv b/data/users.csv new file mode 100644 index 0000000..a84df42 --- /dev/null +++ b/data/users.csv @@ -0,0 +1,11 @@ +id,name,email,age,department,salary,join_date +1,John Doe,john.doe@example.com,28,Engineering,75000,2022-01-15 +2,Jane Smith,jane.smith@example.com,32,Marketing,68000,2021-03-20 +3,Bob Johnson,bob.johnson@example.com,45,Sales,82000,2020-07-10 +4,Alice Brown,alice.brown@example.com,29,Engineering,78000,2022-05-08 +5,Charlie Davis,charlie.davis@example.com,35,HR,65000,2021-11-12 +6,Eva Wilson,eva.wilson@example.com,27,Design,72000,2022-09-03 +7,Frank Miller,frank.miller@example.com,38,Engineering,85000,2020-12-01 +8,Grace Lee,grace.lee@example.com,31,Marketing,70000,2021-08-18 +9,Henry Taylor,henry.taylor@example.com,26,Sales,62000,2023-02-14 +10,Ivy Chen,ivy.chen@example.com,33,Engineering,80000,2021-06-25 \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..62b8f2b --- /dev/null +++ b/main.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +""" +Main application entry point for the sandbox project. +""" + +import json +import os +from datetime import datetime + +def load_config(): + """Load configuration from config.json""" + try: + with open('config.json', 'r') as f: + return json.load(f) + except FileNotFoundError: + return {"debug": True, "version": "1.0.0"} + +def main(): + """Main function""" + config = load_config() + print(f"Sandbox Project v{config.get('version', '1.0.0')}") + print(f"Debug mode: {config.get('debug', False)}") + print(f"Current time: {datetime.now()}") + + if config.get("debug"): + print("Running in debug mode") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..e207a89 --- /dev/null +++ b/package.json @@ -0,0 +1,38 @@ +{ + "name": "sandbox-project", + "version": "1.0.0", + "description": "A Git playground for testing various Git features and workflows", + "main": "main.py", + "scripts": { + "start": "python main.py", + "test": "pytest tests/", + "lint": "eslint src/*.js", + "build": "echo 'Building project...'", + "clean": "rm -rf __pycache__ *.pyc" + }, + "keywords": [ + "git", + "playground", + "testing", + "sandbox" + ], + "author": "Sandbox Team", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21", + "moment": "^2.29.4" + }, + "devDependencies": { + "eslint": "^8.0.0", + "jest": "^29.0.0", + "prettier": "^2.8.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/example/sandbox-project.git" + }, + "bugs": { + "url": "https://github.com/example/sandbox-project/issues" + }, + "homepage": "https://github.com/example/sandbox-project#readme" +} \ No newline at end of file diff --git a/scripts/deploy.sh b/scripts/deploy.sh new file mode 100755 index 0000000..45a47bb --- /dev/null +++ b/scripts/deploy.sh @@ -0,0 +1,71 @@ +#!/bin/bash + +# Deployment script for sandbox project + +set -e # Exit on any error + +echo "Starting deployment process..." + +# Configuration +ENVIRONMENT=${1:-development} +BUILD_DIR="./build" +BACKUP_DIR="./backups" + +echo "Environment: $ENVIRONMENT" + +# Create necessary directories +mkdir -p $BUILD_DIR +mkdir -p $BACKUP_DIR + +# Backup current deployment +if [ -d "$BUILD_DIR/current" ]; then + echo "Creating backup of current deployment..." + timestamp=$(date +%Y%m%d_%H%M%S) + cp -r $BUILD_DIR/current $BACKUP_DIR/backup_$timestamp +fi + +# Build the project +echo "Building project..." +if [ -f "package.json" ]; then + npm install + npm run build +fi + +# Run tests +echo "Running tests..." +if [ -f "package.json" ]; then + npm test +fi + +if [ -f "requirements.txt" ]; then + pip install -r requirements.txt + pytest tests/ || echo "Python tests not found, skipping..." +fi + +# Deploy +echo "Deploying to $ENVIRONMENT..." +case $ENVIRONMENT in + "production") + echo "Production deployment - implementing safety checks..." + # Add production-specific deployment steps + ;; + "staging") + echo "Staging deployment..." + # Add staging-specific deployment steps + ;; + "development") + echo "Development deployment..." + # Add development-specific deployment steps + ;; + *) + echo "Unknown environment: $ENVIRONMENT" + exit 1 + ;; +esac + +# Health check +echo "Performing health check..." +# Add health check logic here + +echo "Deployment completed successfully!" +echo "Deployed at: $(date)" \ No newline at end of file diff --git a/src/StringHelper.java b/src/StringHelper.java new file mode 100644 index 0000000..a288737 --- /dev/null +++ b/src/StringHelper.java @@ -0,0 +1,74 @@ +package src; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * String utility class for various string operations + */ +public class StringHelper { + + /** + * Reverses a string + */ + public static String reverse(String str) { + if (str == null || str.isEmpty()) { + return str; + } + return new StringBuilder(str).reverse().toString(); + } + + /** + * Counts word occurrences in a string + */ + public static Map wordCount(String text) { + if (text == null || text.trim().isEmpty()) { + return new HashMap<>(); + } + + return Arrays.stream(text.toLowerCase().split("\\s+")) + .filter(word -> !word.isEmpty()) + .collect(Collectors.toMap( + word -> word, + word -> 1, + Integer::sum + )); + } + + /** + * Checks if a string is a palindrome + */ + public static boolean isPalindrome(String str) { + if (str == null) { + return false; + } + + String cleaned = str.replaceAll("[^a-zA-Z0-9]", "").toLowerCase(); + return cleaned.equals(reverse(cleaned)); + } + + /** + * Capitalizes the first letter of each word + */ + public static String titleCase(String str) { + if (str == null || str.isEmpty()) { + return str; + } + + return Arrays.stream(str.split("\\s+")) + .map(word -> word.isEmpty() ? word : + Character.toUpperCase(word.charAt(0)) + + word.substring(1).toLowerCase()) + .collect(Collectors.joining(" ")); + } + + /** + * Main method for testing + */ + public static void main(String[] args) { + System.out.println("Testing StringHelper:"); + System.out.println("Reverse 'hello': " + reverse("hello")); + System.out.println("Is 'racecar' palindrome: " + isPalindrome("racecar")); + System.out.println("Title case 'hello world': " + titleCase("hello world")); + } +} \ No newline at end of file diff --git a/src/calculator.js b/src/calculator.js new file mode 100644 index 0000000..487ee87 --- /dev/null +++ b/src/calculator.js @@ -0,0 +1,46 @@ +/** + * Simple calculator module for testing JavaScript functionality + */ + +class Calculator { + constructor() { + this.history = []; + } + + add(a, b) { + const result = a + b; + this.history.push(`${a} + ${b} = ${result}`); + return result; + } + + subtract(a, b) { + const result = a - b; + this.history.push(`${a} - ${b} = ${result}`); + return result; + } + + multiply(a, b) { + const result = a * b; + this.history.push(`${a} * ${b} = ${result}`); + return result; + } + + divide(a, b) { + if (b === 0) { + throw new Error("Division by zero is not allowed"); + } + const result = a / b; + this.history.push(`${a} / ${b} = ${result}`); + return result; + } + + getHistory() { + return this.history.slice(); + } + + clearHistory() { + this.history = []; + } +} + +module.exports = Calculator; \ No newline at end of file diff --git a/src/data_structures.go b/src/data_structures.go new file mode 100644 index 0000000..e8a3479 --- /dev/null +++ b/src/data_structures.go @@ -0,0 +1,140 @@ +package main + +import ( + "fmt" + "sort" +) + +// Stack implementation +type Stack struct { + items []int +} + +func (s *Stack) Push(item int) { + s.items = append(s.items, item) +} + +func (s *Stack) Pop() (int, bool) { + if len(s.items) == 0 { + return 0, false + } + item := s.items[len(s.items)-1] + s.items = s.items[:len(s.items)-1] + return item, true +} + +func (s *Stack) IsEmpty() bool { + return len(s.items) == 0 +} + +// Queue implementation +type Queue struct { + items []int +} + +func (q *Queue) Enqueue(item int) { + q.items = append(q.items, item) +} + +func (q *Queue) Dequeue() (int, bool) { + if len(q.items) == 0 { + return 0, false + } + item := q.items[0] + q.items = q.items[1:] + return item, true +} + +func (q *Queue) IsEmpty() bool { + return len(q.items) == 0 +} + +// Binary search +func binarySearch(arr []int, target int) int { + sort.Ints(arr) + left, right := 0, len(arr)-1 + + for left <= right { + mid := left + (right-left)/2 + if arr[mid] == target { + return mid + } else if arr[mid] < target { + left = mid + 1 + } else { + right = mid - 1 + } + } + return -1 +} + +// Merge sort +func mergeSort(arr []int) []int { + if len(arr) <= 1 { + return arr + } + + mid := len(arr) / 2 + left := mergeSort(arr[:mid]) + right := mergeSort(arr[mid:]) + + return merge(left, right) +} + +func merge(left, right []int) []int { + result := make([]int, 0, len(left)+len(right)) + i, j := 0, 0 + + for i < len(left) && j < len(right) { + if left[i] <= right[j] { + result = append(result, left[i]) + i++ + } else { + result = append(result, right[j]) + j++ + } + } + + result = append(result, left[i:]...) + result = append(result, right[j:]...) + + return result +} + +func main() { + // Test Stack + stack := &Stack{} + stack.Push(1) + stack.Push(2) + stack.Push(3) + + fmt.Println("Stack operations:") + for !stack.IsEmpty() { + if item, ok := stack.Pop(); ok { + fmt.Printf("Popped: %d\n", item) + } + } + + // Test Queue + queue := &Queue{} + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + + fmt.Println("\nQueue operations:") + for !queue.IsEmpty() { + if item, ok := queue.Dequeue(); ok { + fmt.Printf("Dequeued: %d\n", item) + } + } + + // Test binary search and merge sort + arr := []int{64, 34, 25, 12, 22, 11, 90} + fmt.Printf("\nOriginal array: %v\n", arr) + + sorted := mergeSort(arr) + fmt.Printf("Sorted array: %v\n", sorted) + + target := 25 + index := binarySearch(sorted, target) + fmt.Printf("Binary search for %d: index %d\n", target, index) +} \ No newline at end of file diff --git a/src/math_ops.cpp b/src/math_ops.cpp new file mode 100644 index 0000000..cbd68f2 --- /dev/null +++ b/src/math_ops.cpp @@ -0,0 +1,81 @@ +#include +#include +#include +#include + +/** + * Mathematical operations library + */ +namespace MathOps { + + // Calculate factorial + long long factorial(int n) { + if (n <= 1) return 1; + long long result = 1; + for (int i = 2; i <= n; ++i) { + result *= i; + } + return result; + } + + // Check if number is prime + bool isPrime(int n) { + if (n <= 1) return false; + if (n <= 3) return true; + if (n % 2 == 0 || n % 3 == 0) return false; + + for (int i = 5; i * i <= n; i += 6) { + if (n % i == 0 || n % (i + 2) == 0) { + return false; + } + } + return true; + } + + // Find GCD using Euclidean algorithm + int gcd(int a, int b) { + while (b != 0) { + int temp = b; + b = a % b; + a = temp; + } + return a; + } + + // Calculate mean of vector + double mean(const std::vector& numbers) { + if (numbers.empty()) return 0.0; + double sum = 0.0; + for (double num : numbers) { + sum += num; + } + return sum / numbers.size(); + } + + // Calculate standard deviation + double standardDeviation(const std::vector& numbers) { + if (numbers.size() <= 1) return 0.0; + + double avg = mean(numbers); + double sum_squared_diff = 0.0; + + for (double num : numbers) { + sum_squared_diff += (num - avg) * (num - avg); + } + + return std::sqrt(sum_squared_diff / (numbers.size() - 1)); + } +} + +int main() { + std::cout << "Math Operations Demo:" << std::endl; + std::cout << "Factorial of 5: " << MathOps::factorial(5) << std::endl; + std::cout << "Is 17 prime? " << (MathOps::isPrime(17) ? "Yes" : "No") << std::endl; + std::cout << "GCD of 48 and 18: " << MathOps::gcd(48, 18) << std::endl; + + std::vector numbers = {1.0, 2.0, 3.0, 4.0, 5.0}; + std::cout << "Mean of [1,2,3,4,5]: " << MathOps::mean(numbers) << std::endl; + std::cout << "Std dev of [1,2,3,4,5]: " << MathOps::standardDeviation(numbers) << std::endl; + + return 0; +} \ No newline at end of file diff --git a/src/utils.py b/src/utils.py new file mode 100644 index 0000000..07e3146 --- /dev/null +++ b/src/utils.py @@ -0,0 +1,54 @@ +""" +Utility functions for the sandbox project +""" + +import hashlib +import random +import string +from typing import List, Dict, Any + +def generate_random_string(length: int = 10) -> str: + """Generate a random string of specified length""" + letters = string.ascii_lowercase + string.digits + return ''.join(random.choice(letters) for _ in range(length)) + +def hash_string(text: str, algorithm: str = 'sha256') -> str: + """Hash a string using the specified algorithm""" + hash_obj = hashlib.new(algorithm) + hash_obj.update(text.encode('utf-8')) + return hash_obj.hexdigest() + +def flatten_dict(d: Dict[str, Any], parent_key: str = '', sep: str = '.') -> Dict[str, Any]: + """Flatten a nested dictionary""" + items = [] + for k, v in d.items(): + new_key = f"{parent_key}{sep}{k}" if parent_key else k + if isinstance(v, dict): + items.extend(flatten_dict(v, new_key, sep=sep).items()) + else: + items.append((new_key, v)) + return dict(items) + +def chunk_list(lst: List[Any], chunk_size: int) -> List[List[Any]]: + """Split a list into chunks of specified size""" + return [lst[i:i + chunk_size] for i in range(0, len(lst), chunk_size)] + +class DataProcessor: + """A class for processing various data types""" + + def __init__(self): + self.processed_count = 0 + + def process_numbers(self, numbers: List[float]) -> Dict[str, float]: + """Process a list of numbers and return statistics""" + if not numbers: + return {} + + self.processed_count += 1 + return { + 'count': len(numbers), + 'sum': sum(numbers), + 'average': sum(numbers) / len(numbers), + 'min': min(numbers), + 'max': max(numbers) + } \ No newline at end of file diff --git a/tests/unit/test_calculator.js b/tests/unit/test_calculator.js new file mode 100644 index 0000000..292c59e --- /dev/null +++ b/tests/unit/test_calculator.js @@ -0,0 +1,53 @@ +const Calculator = require('../../src/calculator'); + +describe('Calculator', () => { + let calculator; + + beforeEach(() => { + calculator = new Calculator(); + }); + + test('should add two numbers correctly', () => { + expect(calculator.add(2, 3)).toBe(5); + expect(calculator.add(-1, 1)).toBe(0); + expect(calculator.add(0, 0)).toBe(0); + }); + + test('should subtract two numbers correctly', () => { + expect(calculator.subtract(5, 3)).toBe(2); + expect(calculator.subtract(1, 1)).toBe(0); + expect(calculator.subtract(0, 5)).toBe(-5); + }); + + test('should multiply two numbers correctly', () => { + expect(calculator.multiply(3, 4)).toBe(12); + expect(calculator.multiply(-2, 3)).toBe(-6); + expect(calculator.multiply(0, 5)).toBe(0); + }); + + test('should divide two numbers correctly', () => { + expect(calculator.divide(10, 2)).toBe(5); + expect(calculator.divide(7, 2)).toBe(3.5); + expect(calculator.divide(-6, 3)).toBe(-2); + }); + + test('should throw error when dividing by zero', () => { + expect(() => calculator.divide(5, 0)).toThrow('Division by zero is not allowed'); + }); + + test('should maintain calculation history', () => { + calculator.add(2, 3); + calculator.multiply(4, 5); + + const history = calculator.getHistory(); + expect(history).toHaveLength(2); + expect(history[0]).toBe('2 + 3 = 5'); + expect(history[1]).toBe('4 * 5 = 20'); + }); + + test('should clear history', () => { + calculator.add(1, 1); + calculator.clearHistory(); + expect(calculator.getHistory()).toHaveLength(0); + }); +}); \ No newline at end of file diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py new file mode 100644 index 0000000..85a3f53 --- /dev/null +++ b/tests/unit/test_utils.py @@ -0,0 +1,101 @@ +import pytest +import sys +import os + +# Add src directory to path for imports +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', 'src')) + +from utils import generate_random_string, hash_string, flatten_dict, chunk_list, DataProcessor + +class TestUtils: + + def test_generate_random_string(self): + # Test default length + result = generate_random_string() + assert len(result) == 10 + assert result.isalnum() + + # Test custom length + result = generate_random_string(5) + assert len(result) == 5 + + # Test uniqueness + result1 = generate_random_string(20) + result2 = generate_random_string(20) + assert result1 != result2 + + def test_hash_string(self): + # Test SHA256 (default) + result = hash_string("hello") + assert len(result) == 64 # SHA256 produces 64 character hex string + + # Test MD5 + result = hash_string("hello", "md5") + assert len(result) == 32 # MD5 produces 32 character hex string + + # Test consistency + result1 = hash_string("test") + result2 = hash_string("test") + assert result1 == result2 + + def test_flatten_dict(self): + nested = { + "a": 1, + "b": { + "c": 2, + "d": { + "e": 3 + } + } + } + + expected = { + "a": 1, + "b.c": 2, + "b.d.e": 3 + } + + result = flatten_dict(nested) + assert result == expected + + # Test custom separator + result = flatten_dict(nested, sep="_") + assert "b_c" in result + assert "b_d_e" in result + + def test_chunk_list(self): + data = [1, 2, 3, 4, 5, 6, 7, 8, 9] + + result = chunk_list(data, 3) + expected = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] + assert result == expected + + # Test uneven chunks + result = chunk_list(data, 4) + expected = [[1, 2, 3, 4], [5, 6, 7, 8], [9]] + assert result == expected + + # Test empty list + result = chunk_list([], 3) + assert result == [] + +class TestDataProcessor: + + def test_process_numbers(self): + processor = DataProcessor() + numbers = [1.0, 2.0, 3.0, 4.0, 5.0] + + result = processor.process_numbers(numbers) + + assert result['count'] == 5 + assert result['sum'] == 15.0 + assert result['average'] == 3.0 + assert result['min'] == 1.0 + assert result['max'] == 5.0 + assert processor.processed_count == 1 + + def test_process_numbers_empty_list(self): + processor = DataProcessor() + result = processor.process_numbers([]) + assert result == {} + assert processor.processed_count == 0 \ No newline at end of file