# Test Coverage Analysis: downloader.rs

Repository: https://github.com/loonghao/vx
Branch: feat/bundled-runtime-version-propagation
File: crates/vx-installer/src/downloader.rs
File Size: 648 lines
Public API: 26 methods

SUMMARY
=======

The downloader.rs file contains HTTP download utilities with advanced features:
- CDN acceleration with fallback URLs
- Exponential backoff retry logic (backon crate)
- Checksum verification (SHA256)
- Content-Disposition header parsing
- Progress tracking integration
- Streaming downloads with chunk processing

Current Test Coverage:
- Existing Tests: 3 unit tests in file
  1. test_extract_filename_from_url() - Basic URL parsing
  2. test_download_config() - Configuration builder pattern
  3. test_retry_strategy() - Retry configuration

- Coverage: ~12% of public methods (3 of 26)


CRITICAL GAPS - No Tests
========================

1. Constructor Variants (5 methods)
   - with_cdn(bool)
   - with_timeout(Duration, bool)
   - with_client(Client)
   - with_client_and_cdn(Client, CdnOptimizer)
   - is_cdn_enabled() / set_cdn_enabled()

2. Content-Disposition Parsing (1 method)
   The parse_content_disposition() function handles RFC 5987-compliant headers
   Test cases needed:
   - Standard: filename=xxx.zip
   - Quoted: filename="xxx.zip"
   - RFC 5987 encoded: filename*=UTF-8''OpenJDK25U.zip
   - URL-encoded special characters
   - Empty/invalid headers
   - Multiple filename parameters

3. SHA256 Checksum Calculation (1 method)
   The calculate_sha256() function needs tests for:
   - Small files
   - Large files
   - Binary files
   - Empty files
   - Non-existent files (error case)

4. URL Filename Extraction (already partially tested - needs expansion)
   Additional edge cases:
   - URLs with fragments (#)
   - Complex query strings (multiple ? & params)
   - Empty filenames
   - Unicode characters

5. Async Download Methods (5 methods)
   Require mocking HTTP responses (use wiremock or mockito):
   - download() - async
   - download_temp() - async
   - download_with_checksum() - async
   - get_file_size() - async
   - check_url() - async

6. Server Metadata Extraction (1 private async method)
   - get_filename_from_server() - needs Content-Disposition header extraction tests

7. DownloadConfig Missing Test (1 method)
   - with_timeout() - currently untested


COVERAGE SUMMARY TABLE
======================

Category                 | Total | Tested | Untested | % Covered
-------------------------|-------|--------|----------|----------
Downloader (public)      |  22   |   3    |   19     |  13.6%
DownloadConfig (public)  |   6   |   5    |    1     |  83.3%
Private methods          |   5   |   0    |    5     |   0%
TOTAL                    |  33   |   8    |   25     |  24.2%


PHASE 1: QUICK WINS (Unit Tests - No Mocking)
=============================================

These are fast, isolated unit tests that should be added first:

1. test_parse_content_disposition_standard()
   - Test: "attachment; filename=archive.zip"
   - Expected: "archive.zip"

2. test_parse_content_disposition_quoted()
   - Test: "attachment; filename=\"my file.zip\""
   - Expected: "my file.zip"

3. test_parse_content_disposition_rfc5987()
   - Test: "attachment; filename*=UTF-8''OpenJDK25U.zip"
   - Expected: "OpenJDK25U.zip"

4. test_parse_content_disposition_empty()
   - Test: "attachment"
   - Expected: None

5. test_calculate_sha256_small_file()
   - Create temp file with "Hello, World!"
   - Expected: dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f

6. test_calculate_sha256_empty_file()
   - Create empty temp file
   - Expected: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

7. test_calculate_sha256_nonexistent_file()
   - Verify error when file doesn't exist

8. test_downloader_new_creates_default()
   - Verify CDN not enabled by default
   - Verify max_retries = 5

9. test_downloader_with_cdn_enabled()
   - Create downloader with CDN enabled
   - Verify is_cdn_enabled() returns true

10. test_downloader_with_cdn_disabled()
    - Create downloader with CDN disabled
    - Verify is_cdn_enabled() returns false

11. test_downloader_set_cdn_enabled()
    - Test toggling CDN enabled/disabled
    - Verify state changes correctly

12. test_download_config_with_timeout()
    - Create config with custom timeout
    - Verify timeout is set correctly


PHASE 2: Integration Tests (HTTP Mocking)
==========================================

File: tests/downloader_integration_tests.rs

Recommended library: wiremock-rs (modern, flexible)

Tests needed:
1. test_download_success()
   - Mock HTTP 200 response with content
   - Verify file is downloaded

2. test_download_retry_on_network_error()
   - Mock first request fails, second succeeds
   - Verify retry logic works

3. test_download_fallback_to_original_url()
   - Primary CDN URL fails, fallback succeeds
   - Verify fallback mechanism works

4. test_download_checksum_mismatch()
   - Download file with mismatched checksum
   - Verify proper error returned

5. test_get_file_size_success()
   - Mock HEAD request with Content-Length
   - Verify size extracted correctly

6. test_check_url_accessible()
   - Mock successful HEAD request
   - Verify URL is accessible

7. test_get_filename_from_content_disposition()
   - Mock response with Content-Disposition header
   - Verify filename extracted correctly


PHASE 3: Property-Based Tests (Optional)
=========================================

Use proptest crate for fuzzing:

1. prop_extract_filename_never_panics()
   - Fuzz with arbitrary strings
   - Verify function never panics

2. prop_parse_disposition_never_panics()
   - Fuzz with arbitrary strings
   - Verify function never panics


DEPENDENCIES TO ADD
===================

In Cargo.toml [dev-dependencies]:
- wiremock = "0.5"  # HTTP mocking
- proptest = "1.0"  # Property-based testing


CHANGES IN PR BRANCH
====================

The only code change in this branch is a formatting fix in calculate_sha256():
- Reformatted the hasher.finalize().iter().fold() chain for better readability
- No functional changes, so existing tests remain valid
- No new logic requiring new tests

This is purely a style/formatting change affecting line 526-537.
