diff --git a/cache_spec.lua b/cache_spec.lua new file mode 100644 index 0000000..ce8ad5c --- /dev/null +++ b/cache_spec.lua @@ -0,0 +1,55 @@ +-- Unit tests for caching system +describe('cp.cache', function() + local cache + local temp_dir + + before_each(function() + cache = require('cp.cache') + temp_dir = vim.fn.tempname() + vim.fn.mkdir(temp_dir, 'p') + -- Mock cache directory + end) + + after_each(function() + -- Clean up temp files + vim.fn.delete(temp_dir, 'rf') + end) + + describe('contest metadata caching', function() + it('stores contest metadata correctly', function() + -- Test storing contest data + end) + + it('retrieves cached contest metadata', function() + -- Test retrieving contest data + end) + + it('handles missing cache files gracefully', function() + -- Test missing cache behavior + end) + end) + + describe('test case caching', function() + it('stores test cases for problems', function() + -- Test test case storage + end) + + it('retrieves cached test cases', function() + -- Test test case retrieval + end) + + it('handles cache invalidation', function() + -- Test cache expiry/invalidation + end) + end) + + describe('cache persistence', function() + it('persists cache across sessions', function() + -- Test cache file persistence + end) + + it('handles corrupted cache files', function() + -- Test corrupted cache recovery + end) + end) +end) diff --git a/command_parsing_spec.lua b/command_parsing_spec.lua new file mode 100644 index 0000000..0abef2b --- /dev/null +++ b/command_parsing_spec.lua @@ -0,0 +1,79 @@ +-- Unit tests for command parsing and validation +describe('cp command parsing', function() + local cp + + before_each(function() + cp = require('cp') + cp.setup() + end) + + describe('platform setup commands', function() + it('parses :CP codeforces correctly', function() + -- Test platform-only command parsing + end) + + it('parses :CP codeforces 1800 correctly', function() + -- Test contest setup command parsing + end) + + it('parses :CP codeforces 1800 A correctly', function() + -- Test full setup command parsing + end) + + it('parses CSES format :CP cses 1068 correctly', function() + -- Test CSES-specific command parsing + end) + end) + + describe('action commands', function() + it('parses :CP test correctly', function() + -- Test test panel command + end) + + it('parses :CP next correctly', function() + -- Test navigation command + end) + + it('parses :CP prev correctly', function() + -- Test navigation command + end) + end) + + describe('language flags', function() + it('parses --lang=cpp correctly', function() + -- Test language flag parsing + end) + + it('parses --debug flag correctly', function() + -- Test debug flag parsing + end) + + it('combines flags correctly', function() + -- Test multiple flag parsing + end) + end) + + describe('error handling', function() + it('handles invalid commands gracefully', function() + -- Test error messages for bad commands + end) + + it('provides helpful error messages', function() + -- Test error message quality + end) + end) + + describe('command completion', function() + it('completes platform names', function() + -- Test tab completion for platforms + end) + + it('completes problem IDs from cached contest', function() + -- Test problem ID completion + end) + + it('completes action names', function() + -- Test action completion + end) + end) +end) diff --git a/config_spec.lua b/config_spec.lua new file mode 100644 index 0000000..ae1c46a --- /dev/null +++ b/config_spec.lua @@ -0,0 +1,46 @@ +-- Unit tests for configuration management +describe('cp.config', function() + local config + + before_each(function() + config = require('cp.config') + end) + + describe('setup', function() + it('returns default config when no user config provided', function() + -- Test default configuration values + end) + + it('merges user config with defaults', function() + -- Test config merging behavior + end) + + it('validates contest configurations', function() + -- Test contest config validation + end) + + it('handles invalid config gracefully', function() + -- Test error handling for bad configs + end) + end) + + describe('platform validation', function() + it('accepts valid platforms', function() + -- Test platform validation + end) + + it('rejects invalid platforms', function() + -- Test platform rejection + end) + end) + + describe('language configurations', function() + it('provides correct file extensions for languages', function() + -- Test language -> extension mappings + end) + + it('provides correct compile commands', function() + -- Test compile command generation + end) + end) +end) diff --git a/execute_spec.lua b/execute_spec.lua new file mode 100644 index 0000000..e48447f --- /dev/null +++ b/execute_spec.lua @@ -0,0 +1,108 @@ +-- Unit tests for code compilation and execution +describe('cp.execute', function() + local execute + local temp_dir + local test_files = {} + + before_each(function() + execute = require('cp.execute') + temp_dir = vim.fn.tempname() + vim.fn.mkdir(temp_dir, 'p') + vim.api.nvim_set_current_dir(temp_dir) + + -- Create sample source files for testing + test_files.cpp = temp_dir .. '/test.cpp' + test_files.python = temp_dir .. '/test.py' + test_files.rust = temp_dir .. '/test.rs' + + -- Write simple test programs + vim.fn.writefile({ + '#include ', + 'int main() { std::cout << "Hello" << std::endl; return 0; }', + }, test_files.cpp) + + vim.fn.writefile({ + 'print("Hello")', + }, test_files.python) + end) + + after_each(function() + vim.fn.delete(temp_dir, 'rf') + end) + + describe('compilation', function() + it('compiles C++ code successfully', function() + -- Test C++ compilation + end) + + it('compiles Rust code successfully', function() + -- Test Rust compilation + end) + + it('handles compilation errors', function() + -- Test error handling for bad code + end) + + it('applies optimization flags correctly', function() + -- Test optimization settings + end) + + it('handles debug flag correctly', function() + -- Test debug compilation + end) + end) + + describe('execution', function() + it('runs compiled programs', function() + -- Test program execution + end) + + it('handles runtime errors', function() + -- Test runtime error handling + end) + + it('enforces time limits', function() + -- Test timeout handling + end) + + it('captures output correctly', function() + -- Test stdout/stderr capture + end) + + it('handles large inputs/outputs', function() + -- Test large data handling + end) + end) + + describe('test case execution', function() + it('runs single test case', function() + -- Test individual test case execution + end) + + it('runs multiple test cases', function() + -- Test batch execution + end) + + it('compares outputs correctly', function() + -- Test output comparison logic + end) + + it('handles edge cases in output comparison', function() + -- Test whitespace, newlines, etc. + end) + end) + + describe('platform-specific execution', function() + it('works on Linux', function() + -- Test Linux-specific behavior + end) + + it('works on macOS', function() + -- Test macOS-specific behavior + end) + + it('works on Windows', function() + -- Test Windows-specific behavior + end) + end) +end) diff --git a/health_spec.lua b/health_spec.lua new file mode 100644 index 0000000..8f43778 --- /dev/null +++ b/health_spec.lua @@ -0,0 +1,54 @@ +-- Unit tests for health check functionality +describe('cp.health', function() + local health + + before_each(function() + health = require('cp.health') + end) + + describe('system checks', function() + it('detects Neovim version correctly', function() + -- Test Neovim version detection + end) + + it('detects available compilers', function() + -- Test C++, Rust, etc. compiler detection + end) + + it('detects Python installation', function() + -- Test Python availability + end) + + it('checks for required external tools', function() + -- Test curl, wget, etc. availability + end) + end) + + describe('configuration validation', function() + it('validates contest configurations', function() + -- Test config validation + end) + + it('checks directory permissions', function() + -- Test write permissions for directories + end) + + it('validates language configurations', function() + -- Test language setup validation + end) + end) + + describe('health report generation', function() + it('generates comprehensive health report', function() + -- Test :checkhealth cp output + end) + + it('provides actionable recommendations', function() + -- Test that health check gives useful advice + end) + + it('handles partial functionality gracefully', function() + -- Test when some features are unavailable + end) + end) +end) diff --git a/integration_spec.lua b/integration_spec.lua new file mode 100644 index 0000000..8570d2f --- /dev/null +++ b/integration_spec.lua @@ -0,0 +1,114 @@ +-- Integration tests for complete workflows +describe('cp.nvim integration', function() + local cp + local temp_dir + + before_each(function() + cp = require('cp') + temp_dir = vim.fn.tempname() + vim.fn.mkdir(temp_dir, 'p') + vim.api.nvim_set_current_dir(temp_dir) + + -- Set up with minimal config + cp.setup({ + scrapers = {}, -- Disable scraping for integration tests + contests = { + codeforces = { + dir = temp_dir, + url = 'mock://codeforces.com', + languages = { + cpp = { extension = 'cpp', compile = 'g++ -o %s %s' }, + }, + }, + }, + }) + end) + + after_each(function() + vim.fn.delete(temp_dir, 'rf') + vim.cmd('silent! %bwipeout!') + end) + + describe('complete problem setup workflow', function() + it('handles :CP codeforces 1800 A workflow', function() + -- Test complete setup from command to file creation + -- 1. Parse command + -- 2. Set up directory structure + -- 3. Create source file + -- 4. Apply template + -- 5. Switch to buffer + end) + + it('handles CSES workflow', function() + -- Test CSES-specific complete workflow + end) + + it('handles language switching', function() + -- Test switching languages for same problem + end) + end) + + describe('problem navigation workflow', function() + it('navigates between problems in contest', function() + -- Test :CP next/:CP prev workflow + -- Requires cached contest metadata + end) + + it('maintains state across navigation', function() + -- Test that work isn't lost when switching problems + end) + end) + + describe('test panel workflow', function() + it('handles complete testing workflow', function() + -- 1. Set up problem + -- 2. Write solution + -- 3. Open test panel (:CP test) + -- 4. Compile and run tests + -- 5. View results + -- 6. Close panel + end) + + it('handles debug workflow', function() + -- Test :CP test --debug workflow + end) + end) + + describe('file system integration', function() + it('maintains proper directory structure', function() + -- Test that files are organized correctly + end) + + it('handles existing files appropriately', function() + -- Test behavior when problem already exists + end) + + it('cleans up temporary files', function() + -- Test cleanup of build artifacts + end) + end) + + describe('error recovery', function() + it('recovers from network failures gracefully', function() + -- Test behavior when scraping fails + end) + + it('recovers from compilation failures', function() + -- Test error handling in compilation + end) + + it('handles corrupted cache gracefully', function() + -- Test cache corruption recovery + end) + end) + + describe('multi-session behavior', function() + it('persists state across Neovim restarts', function() + -- Test that contest/problem state persists + end) + + it('handles concurrent usage', function() + -- Test multiple Neovim instances + end) + end) +end) diff --git a/plugin/cp.lua b/plugin/cp.lua index 7a21718..2bf4707 100644 --- a/plugin/cp.lua +++ b/plugin/cp.lua @@ -3,10 +3,6 @@ if vim.g.loaded_cp then end vim.g.loaded_cp = 1 -local constants = require('cp.constants') -local platforms = constants.PLATFORMS -local actions = constants.ACTIONS - vim.api.nvim_create_user_command('CP', function(opts) local cp = require('cp') cp.handle_command(opts) @@ -14,6 +10,10 @@ end, { nargs = '*', desc = 'Competitive programming helper', complete = function(ArgLead, CmdLine, _) + local constants = require('cp.constants') + local platforms = constants.PLATFORMS + local actions = constants.ACTIONS + local args = vim.split(vim.trim(CmdLine), '%s+') local num_args = #args if CmdLine:sub(-1) == ' ' then diff --git a/problem_spec.lua b/problem_spec.lua new file mode 100644 index 0000000..c895be9 --- /dev/null +++ b/problem_spec.lua @@ -0,0 +1,81 @@ +-- Unit tests for problem context and file management +describe('cp.problem', function() + local problem + local temp_dir + + before_each(function() + problem = require('cp.problem') + temp_dir = vim.fn.tempname() + vim.fn.mkdir(temp_dir, 'p') + -- Change to temp directory for testing + vim.api.nvim_set_current_dir(temp_dir) + end) + + after_each(function() + vim.fn.delete(temp_dir, 'rf') + end) + + describe('context creation', function() + it('creates context for Codeforces problems', function() + -- Test context creation with proper paths + end) + + it('creates context for CSES problems', function() + -- Test CSES-specific context + end) + + it('generates correct file paths', function() + -- Test source file path generation + end) + + it('generates correct build paths', function() + -- Test build directory structure + end) + end) + + describe('template handling', function() + it('applies language templates correctly', function() + -- Test template application + end) + + it('handles custom templates', function() + -- Test user-defined templates + end) + + it('supports snippet integration', function() + -- Test LuaSnip integration + end) + end) + + describe('file operations', function() + it('creates directory structure', function() + -- Test directory creation (build/, io/) + end) + + it('handles existing files gracefully', function() + -- Test behavior when files exist + end) + + it('sets up input/output files', function() + -- Test I/O file creation + end) + end) + + describe('language support', function() + it('supports C++ compilation', function() + -- Test C++ setup and compilation + end) + + it('supports Python execution', function() + -- Test Python setup + end) + + it('supports Rust compilation', function() + -- Test Rust setup + end) + + it('supports custom language configurations', function() + -- Test user-defined language support + end) + end) +end) diff --git a/scraper_spec.lua b/scraper_spec.lua new file mode 100644 index 0000000..679b4f9 --- /dev/null +++ b/scraper_spec.lua @@ -0,0 +1,86 @@ +-- Unit tests for web scraping functionality +describe('cp.scrape', function() + local scrape + local mock_responses = {} + + before_each(function() + scrape = require('cp.scrape') + + -- Mock HTTP responses for different platforms + mock_responses.codeforces_contest = [[ +
+
Problem A
+
Problem B
+
+ ]] + + mock_responses.codeforces_problem = [[ +
Sample Input
+
Sample Output
+ ]] + end) + + describe('contest metadata scraping', function() + it('scrapes Codeforces contest problems', function() + -- Mock HTTP request, test problem list extraction + end) + + it('scrapes Atcoder contest problems', function() + -- Test Atcoder format + end) + + it('scrapes CSES problem list', function() + -- Test CSES format + end) + + it('handles network errors gracefully', function() + -- Test error handling for failed requests + end) + + it('handles parsing errors gracefully', function() + -- Test error handling for malformed HTML + end) + end) + + describe('problem scraping', function() + it('extracts test cases from Codeforces problems', function() + -- Test test case extraction + end) + + it('handles multiple test cases correctly', function() + -- Test multiple sample inputs/outputs + end) + + it('handles problems with no sample cases', function() + -- Test edge case handling + end) + + it('extracts problem metadata (time limits, etc.)', function() + -- Test metadata extraction + end) + end) + + describe('platform-specific parsing', function() + it('handles Codeforces HTML structure', function() + -- Test Codeforces-specific parsing + end) + + it('handles Atcoder HTML structure', function() + -- Test Atcoder-specific parsing + end) + + it('handles CSES HTML structure', function() + -- Test CSES-specific parsing + end) + end) + + describe('rate limiting and caching', function() + it('respects rate limits', function() + -- Test rate limiting behavior + end) + + it('uses cached results when appropriate', function() + -- Test caching integration + end) + end) +end) diff --git a/snippets_spec.lua b/snippets_spec.lua new file mode 100644 index 0000000..ed81205 --- /dev/null +++ b/snippets_spec.lua @@ -0,0 +1,68 @@ +-- Unit tests for snippet/template functionality +describe('cp.snippets', function() + local snippets + + before_each(function() + snippets = require('cp.snippets') + end) + + describe('template loading', function() + it('loads default templates correctly', function() + -- Test default template loading + end) + + it('loads platform-specific templates', function() + -- Test Codeforces vs CSES templates + end) + + it('loads language-specific templates', function() + -- Test C++ vs Python vs Rust templates + end) + + it('handles custom user templates', function() + -- Test user-defined template integration + end) + end) + + describe('LuaSnip integration', function() + it('registers snippets with LuaSnip', function() + -- Test snippet registration + end) + + it('provides platform-language combinations', function() + -- Test snippet triggers like cp.nvim/codeforces.cpp + end) + + it('handles missing LuaSnip gracefully', function() + -- Test fallback when LuaSnip not available + end) + end) + + describe('template expansion', function() + it('expands templates with correct content', function() + -- Test template content expansion + end) + + it('handles template variables', function() + -- Test variable substitution in templates + end) + + it('maintains cursor positioning', function() + -- Test cursor placement after expansion + end) + end) + + describe('template management', function() + it('allows template customization', function() + -- Test user template override + end) + + it('supports template inheritance', function() + -- Test template extending/modification + end) + + it('validates template syntax', function() + -- Test template validation + end) + end) +end) diff --git a/test_panel_spec.lua b/test_panel_spec.lua new file mode 100644 index 0000000..41de1cc --- /dev/null +++ b/test_panel_spec.lua @@ -0,0 +1,106 @@ +-- UI/buffer tests for the interactive test panel +describe('cp test panel', function() + local cp + + before_each(function() + cp = require('cp') + cp.setup() + -- Set up a clean Neovim environment + vim.cmd('silent! %bwipeout!') + end) + + after_each(function() + -- Clean up test panel state + vim.cmd('silent! %bwipeout!') + end) + + describe('panel creation', function() + it('creates test panel buffers', function() + -- Test buffer creation for tab, expected, actual views + end) + + it('sets up correct window layout', function() + -- Test 3-pane layout creation + end) + + it('applies correct buffer settings', function() + -- Test buffer options (buftype, filetype, etc.) + end) + + it('sets up keymaps correctly', function() + -- Test navigation keymaps (Ctrl+N, Ctrl+P, q) + end) + end) + + describe('test case display', function() + it('renders test case tabs correctly', function() + -- Test tab line rendering with status indicators + end) + + it('displays input correctly', function() + -- Test input pane content + end) + + it('displays expected output correctly', function() + -- Test expected output pane + end) + + it('displays actual output correctly', function() + -- Test actual output pane + end) + + it('shows diff when test fails', function() + -- Test diff mode activation + end) + end) + + describe('navigation', function() + it('navigates to next test case', function() + -- Test Ctrl+N navigation + end) + + it('navigates to previous test case', function() + -- Test Ctrl+P navigation + end) + + it('wraps around at boundaries', function() + -- Test navigation wrapping + end) + + it('updates display on navigation', function() + -- Test content updates when switching tests + end) + end) + + describe('test execution integration', function() + it('compiles and runs tests automatically', function() + -- Test automatic compilation and execution + end) + + it('updates results in real-time', function() + -- Test live result updates + end) + + it('handles compilation failures', function() + -- Test error display when compilation fails + end) + + it('shows execution time', function() + -- Test timing display + end) + end) + + describe('session management', function() + it('saves and restores session correctly', function() + -- Test session save/restore when opening/closing panel + end) + + it('handles multiple panels gracefully', function() + -- Test behavior with multiple test panels + end) + + it('cleans up resources on close', function() + -- Test proper cleanup when closing panel + end) + end) +end)