From 29cb44e967ea31aeccb1f701ed571530e6c60099 Mon Sep 17 00:00:00 2001 From: Jonatas Sas Date: Thu, 31 Jul 2025 11:21:14 -0300 Subject: [PATCH 1/8] chore(release): add v1.4.13 changelog and update CI/CD workflow - Split monolithic CHANGELOG.md into individual files under changelogs/ - Added v1.4.13 entry with documentation and CI/CD updates - Updated release workflow to use per-version changelogs - Enforced minimum coverage (90%) and validated changelog index consistency - Added Markdown coverage report as CI artifact --- .github/workflows/utify.yml | 50 +++-- .gitignore | 7 + CHANGELOG.md | 420 +++--------------------------------- changelogs/1.0.0.md | 6 + changelogs/1.1.0.md | 22 ++ changelogs/1.2.0.md | 21 ++ changelogs/1.3.0.md | 14 ++ changelogs/1.3.1.md | 23 ++ changelogs/1.4.0.md | 102 +++++++++ changelogs/1.4.1.md | 14 ++ changelogs/1.4.10.md | 19 ++ changelogs/1.4.11.md | 11 + changelogs/1.4.12.md | 16 ++ changelogs/1.4.13.md | 16 ++ changelogs/1.4.2.md | 31 +++ changelogs/1.4.3.md | 19 ++ changelogs/1.4.4.md | 6 + changelogs/1.4.5.md | 5 + changelogs/1.4.6.md | 6 + changelogs/1.4.7.md | 7 + changelogs/1.4.8.md | 9 + changelogs/1.4.9.md | 22 ++ 22 files changed, 444 insertions(+), 402 deletions(-) create mode 100644 changelogs/1.0.0.md create mode 100644 changelogs/1.1.0.md create mode 100644 changelogs/1.2.0.md create mode 100644 changelogs/1.3.0.md create mode 100644 changelogs/1.3.1.md create mode 100644 changelogs/1.4.0.md create mode 100644 changelogs/1.4.1.md create mode 100644 changelogs/1.4.10.md create mode 100644 changelogs/1.4.11.md create mode 100644 changelogs/1.4.12.md create mode 100644 changelogs/1.4.13.md create mode 100644 changelogs/1.4.2.md create mode 100644 changelogs/1.4.3.md create mode 100644 changelogs/1.4.4.md create mode 100644 changelogs/1.4.5.md create mode 100644 changelogs/1.4.6.md create mode 100644 changelogs/1.4.7.md create mode 100644 changelogs/1.4.8.md create mode 100644 changelogs/1.4.9.md diff --git a/.github/workflows/utify.yml b/.github/workflows/utify.yml index ec530c2..c89ed80 100644 --- a/.github/workflows/utify.yml +++ b/.github/workflows/utify.yml @@ -45,11 +45,25 @@ jobs: run: go test -v -race -timeout=10m -coverpkg=./... ./tests/integration/... - name: Run benchmarks run: go test -bench=. -benchtime=5s ./tests/benchmarks/... - - name: Fail if coverage is zero + - name: Fail if coverage is below 90% run: | - if [ $(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//') = 0 ]; then - echo "Coverage is 0% - failing." && exit 1 + COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//') + echo "Total coverage: $COVERAGE%" + if (( $(echo "$COVERAGE < 90" | bc -l) )); then + echo "Coverage below 90% - failing." && exit 1 fi + - name: Generate coverage report (Markdown) + run: | + go tool cover -func=coverage.out | tee coverage_report.txt + echo "# Coverage Report" > coverage_report.md + echo '```' >> coverage_report.md + cat coverage_report.txt >> coverage_report.md + echo '```' >> coverage_report.md + - name: Upload coverage report + uses: actions/upload-artifact@v4 + with: + name: coverage-report + path: coverage_report.md - name: Upload coverage reports to Codecov if: github.ref == 'refs/heads/main' uses: codecov/codecov-action@v5 @@ -92,16 +106,32 @@ jobs: version: ${{ steps.get-version.outputs.version }} steps: - uses: actions/checkout@v4 + - name: Get version id: get-version run: | - VERSION="${GITHUB_REF#refs/tags/}" - echo "version=${VERSION}" >> $GITHUB_OUTPUT + RAW_VERSION="${GITHUB_REF#refs/tags/}" # e.g., v1.5.1 + CLEAN_VERSION="${RAW_VERSION#v}" # e.g., 1.5.1 + echo "version=${RAW_VERSION}" >> $GITHUB_OUTPUT + echo "clean_version=${CLEAN_VERSION}" >> $GITHUB_OUTPUT + - name: Validate tag format run: | - if ! [[ "${{ steps.get-version.outputs.version }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+.*$ ]]; then - echo "Invalid version format" && exit 1 + if ! [[ "${{ steps.get-version.outputs.clean_version }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+.*$ ]]; then + echo "Invalid version format: ${{ steps.get-version.outputs.clean_version }}" && exit 1 fi + + - name: Validate changelog file + run: | + FILE="changelogs/${{ steps.get-version.outputs.clean_version }}.md" + if [ ! -f "$FILE" ]; then + echo "Changelog file $FILE not found for this version!" && exit 1 + fi + if ! grep -q "(${FILE})" CHANGELOG.md; then + echo "Changelog file $FILE is missing from the main CHANGELOG.md index!" && exit 1 + fi + cp "$FILE" RELEASE_BODY.md + - name: Build all examples run: | mkdir -p dist/examples @@ -109,11 +139,7 @@ jobs: name=$(basename "$dir") go build -o "dist/examples/$name" "$dir" done - - name: Extract changelog for release - id: changelog - run: | - VERSION="${GITHUB_REF#refs/tags/}" - awk '/## \['"${VERSION}"'\]/{flag=1; next} /^## /{flag=0} flag' CHANGELOG.md > RELEASE_BODY.md + - name: Create or Update GitHub Release uses: softprops/action-gh-release@v2 with: diff --git a/.gitignore b/.gitignore index ede57e9..c34ac2c 100644 --- a/.gitignore +++ b/.gitignore @@ -87,3 +87,10 @@ e2e-sandbox/ /anthropic.json /anthropic.md /ai.config.yml + +############################################################################ +# Coverage +############################################################################ +*.out +coverage.html +*coverage.html diff --git a/CHANGELOG.md b/CHANGELOG.md index b4a8fdc..18f6697 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,390 +1,30 @@ -# Changelog - -## [1.4.12] - 2025-07-31 - -### ๐Ÿš€ Features - -- **Improved Test Suite**: Enhanced test coverage for the `icons` and `logger` packages, ensuring greater reliability and robustness. -- **Test Artifacts Directory**: All files created during tests are now stored in the `tests/data` directory, keeping the project root clean. - -### ๐Ÿ”ง Fixes - -- **Stricter Log Target Handling**: The `SetLogTarget` function now returns an error if the specified log path is not writable, making its behavior more predictable. -- **Improved Test Reliability**: Fixed an issue in the `TestNerdFontDetectionEnvVar` test by exposing the `icons.Init()` function, allowing the test to re-trigger icon detection after modifying environment variables. - -### ๐Ÿ“š Documentation - -- **Updated README.md**: The `README.md` file has been updated to include all the latest features, a new section explaining the example applications, and the "What's New" section has been moved to the beginning of the file for better visibility. -- **Added SECURITY.md**: A `SECURITY.md` file has been added to the `.github` directory, providing clear guidelines for reporting security vulnerabilities. - -## [1.4.11] - 2025-07-30 - -### ๐Ÿงช Testing - -- **Expanded coverage for `utify.go`**: - - Added **table-driven tests** for all formatted getter functions (`Get*f`), covering previously untested methods like `GetSearchf`, `GetUploadf`, etc. - - Added **table-driven tests** for all formatted log-only functions (`Log*f`), covering previously untested methods like `LogSearchf`, `LogUploadf`, etc. - - Introduced tests for **silent mode (`ErrSilent`)** to ensure correct behavior when output is suppressed. - - Added negative tests for **`SetLogTarget`** with invalid paths to validate error handling. -- **Improved test modularity** by splitting new cases into separate blocks for clarity. -- **Target coverage increase**: Pushed coverage for `utify.go` close to 100%. - -## [1.4.10] - 2025-07-29 - -### ๐Ÿงช Testing - -- **Refactored tests for `utify.go`**: - - Split the old `TestAllOutputFunctions` into modular **table-driven tests** for: - - Direct output functions (`Success`, `Error`, `Info`, etc.). - - Formatted output functions (`Successf`, `Errorf`, etc.). - - Getter functions (`Get*`). - - Log-only functions (`Log*`). - - Configuration functions (`SetColorTable`, `SetLogTarget`, `SetLoggingEnabled`, `ForceNerdFont`, etc.). - - Added new tests for **`internal/tests/util.go`** (`CaptureOutput` and `CaptureLogOutput`). -- **Reduced cyclomatic complexity** of tests to comply with `gocyclo`. -- **Package names for tests standardized** to `unit` across the test suite. - -### ๐Ÿ›  Maintenance - -- **Excluded `examples/` folder from coverage** (via `codecov.yml`). -- Unified test style across the repository for better maintainability. - -## [1.4.9] - 2025-07-29 - -### ๐Ÿงช Testing - -- Added **new unit tests** for `utify.go`, improving coverage and reliability. -- Expanded tests to cover **logging-only functions** and **"Get" functions**. - -### ๐Ÿ“š Documentation - -- **Improved doccomments** in `utify.go`: - - Added comprehensive package-level documentation. - - Documented customization features for colors, icons, and logging. - - Clarified usage examples for: - - Direct output functions (e.g., `utify.Success()`) - - Formatted functions (e.g., `utify.Infof()`) - - Getters (e.g., `utify.GetSuccess()`) - - Logging-only functions (e.g., `utify.LogInfo()`) - -### ๐Ÿ›  Maintenance - -- Minor refactoring for **consistency across all message functions**. -- Updated **aliases** for backward compatibility (`MessageType`, `Options`). - -## [1.4.8] - 2025-07-29 - -### ๐Ÿ”’ Security - -- **Added CodeQL Analysis:** Introduced automated CodeQL scans for Go, running on pushes, pull requests, and weekly schedules. - -### ๐Ÿงช Testing - -- **Enhanced Coverage:** Expanded coverage reporting to include all Go packages and added validation to prevent zero-coverage reports. - -## [1.4.7] - 2025-07-29 - -### ๐Ÿ”ง Fixes & Improvements - -- **CI/CD:** Updated Codecov upload step to use `codecov/codecov-action@v5` with explicit `slug` and `token` for reliable coverage reporting. -- **Release Automation:** Enhanced release workflow to extract the correct changelog section automatically and set formatted release titles. -- **Caching:** Updated cache keys across jobs to include `github.sha`, ensuring cache invalidation on code changes. - ---- - -## [1.4.6] - 2025-07-29 - -### ๐Ÿ”ง Fixes - -- **CI/CD:** Corrected `release` job to export the version as an output for dependent jobs. -- **Release Updates:** Ensured the GitHub release step can update existing releases with new artifacts. - ---- - -## [1.4.5] - 2025-07-29 - -### ๐Ÿ”ง Fixes - -- **Permissions:** Added `permissions: contents: write` to enable release updates. - ---- - -## [1.4.4] - 2025-07-29 - -### ๐Ÿ”ง Bug Fixes - -- **CI/CD:** Release workflow now updates existing GitHub releases instead of creating duplicates. -- **Artifacts:** Ensures latest built examples are attached when updating a release. - -## [1.4.3] - 2025-07-29 - -### ๐Ÿš€ Features & Improvements - -- **CI/CD Pipeline Enhancements**: - - Unified workflows into `cicd.yml` combining CI, quality checks, examples build, and release automation. - - Added build process for `examples/` with automatic artifact upload for quick testing. - - Integrated Codecov coverage reports for main branch pushes. - - Separated unit, integration, and benchmark tests with clear visibility. - - Automated Go module publishing to `proxy.golang.org` after tagged releases. - -- **Release Automation**: - - Added automatic changelog generation using `git-chglog`. - - GitHub Releases now include compiled example binaries. - -### ๐Ÿงช Quality & Security - -- **Enhanced Quality Checks**: Strengthened static analysis with `golangci-lint` and cyclomatic complexity validation. -- **Security**: Removed outdated dependencies in workflows and improved token usage for uploads. - ---- - -## [1.4.2] - 2025-07-27 - -### โšก Performance & Code Quality - -- **Code Refactoring**: Reduced cyclomatic complexity for better maintainability - - Refactored `detectNerdFont()` function: Split complex logic into 4 focused functions - - Refactored `Echo()` function: Split formatting logic into 6 specialized functions - - All functions now have complexity โ‰ค 9 (under threshold of 10) - -### ๐Ÿ”ง CI/CD Improvements - -- **Enhanced Workflow Configuration**: Improved GitHub Actions setup - - **Go Version Management**: All workflows now read Go version from `go.mod` file - - **Smart CI Triggering**: Optimized to avoid duplicate runs while ensuring comprehensive coverage - - Runs on: pull requests to main, pushes to main, and tag pushes (releases) - - Codecov uploads on main branch updates and releases - - **Updated Codecov Integration**: Upgraded to `codecov/codecov-action@v5` with better error handling - - **Removed Problematic Dependencies**: Fixed security scanning by removing non-existent packages - -### ๐Ÿ—๏ธ Code Organization - -- **Better Separation of Concerns**: Functions now follow single responsibility principle -- **Improved Readability**: Complex logic broken down into smaller, focused functions -- **Enhanced Maintainability**: Changes can be made to specific functionality without affecting others - -### ๐Ÿงช Quality Assurance - -- **Cyclomatic Complexity**: All functions now pass complexity analysis (gocyclo -over 10) -- **Static Analysis**: Clean staticcheck results -- **Comprehensive Testing**: All unit and integration tests continue to pass -- **Lint Compliance**: Maintains 0 lint issues across all linters - ---- - -## [1.4.1] - 2025-07-27 - -### ๐Ÿ”ง Bug Fixes - -- **Lint Compliance**: Fixed all linting issues for clean code quality - - Fixed 7 `errcheck` violations by properly handling file close operations - - Fixed 1 `ineffassign` violation by removing unused variable assignment - - Updated golangci-lint configuration for modern standards - -### ๐Ÿ—๏ธ Code Quality - -- **Error Handling**: Improved error handling in logger cleanup operations -- **Test Robustness**: Enhanced test cleanup to properly ignore expected errors -- **Linting**: Achieved 0 lint issues across all linters (errcheck, govet, gosimple, staticcheck, unused, revive, gofmt, goimports) - ---- - -## [1.4.0] - 2025-07-27 - -### ๐Ÿš€ Major Features - -- **Modular Architecture**: Complete restructure from single-file to proper Go package organization: - - `pkg/colors/`: ANSI color constants and management - - `pkg/messages/`: Message types and definitions - - `pkg/options/`: Options struct with fluent API - - `pkg/formatter/`: Core formatting logic - - `pkg/logger/`: Structured JSON logging system - - `internal/tests/`: Test utilities - - Organized test structure: unit, integration, and benchmarks - -- **Structured JSON Logging**: Full logging system with configurable targets: - - Default path: `/var/log/{binary_name}.log` (with fallback to current directory) - - JSON format with timestamp, level, message, type, and binary name - - Configurable log target: `SetLogTarget(path)` - - Enable/disable logging: `SetLoggingEnabled(bool)` - - Log file handle management: `CloseLogger()` - -- **Log-Only Functions**: New API for logging without stdout output: - - `LogSuccess()`, `LogError()`, `LogWarning()`, `LogInfo()`, `LogDebug()`, `LogCritical()` - - `LogDelete()`, `LogUpdate()`, `LogInstall()`, `LogUpgrade()`, `LogEdit()`, `LogNew()` - - `LogDownload()`, `LogUpload()`, `LogSync()`, `LogSearch()` - - Formatted versions: `LogSuccessf()`, `LogErrorf()`, etc. - -- **Icon System**: Smart icon display with Nerd Font support: - - Automatic Nerd Font detection via environment variables (`TERM_PROGRAM`, `NERD_FONT_DETECTED`) - - Fallback to regular Unicode icons when Nerd Fonts are not available - - User control: `ForceNerdFont()`, `ForceRegularIcons()`, `DisableIcons()` - - Integration with existing options: `WithIcon()`, `WithoutIcon()` - -### ๐Ÿ”ง Breaking Changes - -- **Package Name**: Changed from `github.com/jonatas-sas/utify` to `github.com/jsas4coding/utify` -- **Go Version**: Bumped to Go 1.24.5 -- **Test Structure**: Moved `internal/testutil/` to `internal/tests/` with package name change - -### โœจ Improvements - -- **Fixed Double Message Bug**: Eliminated duplicate message printing -- **Comprehensive Testing**: Added unit tests, integration tests, and benchmarks -- **Better Examples**: Organized examples into separate directories with dedicated demos -- **Enhanced Documentation**: Updated CLAUDE.md with new architecture details -- **Lint Configuration**: Fixed and simplified revive configuration - -### ๐Ÿ“ฆ New API Functions - -```go -// Logging configuration -SetLogTarget(path string) error -GetLogTarget() string -SetLoggingEnabled(enabled bool) -IsLoggingEnabled() bool -CloseLogger() - -// Log-only functions (no stdout output) -LogSuccess(text string) -LogError(text string) -// ... and all other message types - -// Formatted log-only functions -LogSuccessf(text string, args ...any) -LogErrorf(text string, args ...any) -// ... and all other message types - -// Icon control functions -ForceNerdFont() -ForceRegularIcons() -DisableIcons() -GetIconType() IconType -SetIconType(IconType) -``` - -### ๐Ÿงช Testing - -- **Unit Tests**: Complete coverage for all packages -- **Integration Tests**: API compatibility and functionality verification -- **Benchmarks**: Performance testing for all core functions -- **Test Utilities**: Centralized test helpers for output capture - -### ๐Ÿ“ Project Structure - -``` -utify/ -โ”œโ”€โ”€ pkg/ # Core packages -โ”‚ โ”œโ”€โ”€ colors/ # ANSI colors -โ”‚ โ”œโ”€โ”€ messages/ # Message types -โ”‚ โ”œโ”€โ”€ options/ # Configuration -โ”‚ โ”œโ”€โ”€ formatter/ # Output formatting -โ”‚ โ””โ”€โ”€ logger/ # JSON logging -โ”œโ”€โ”€ internal/tests/ # Test utilities -โ”œโ”€โ”€ examples/ # Usage examples -โ”‚ โ”œโ”€โ”€ basic/ -โ”‚ โ”œโ”€โ”€ colors/ -โ”‚ โ”œโ”€โ”€ callbacks/ -โ”‚ โ””โ”€โ”€ logging-demo/ -โ””โ”€โ”€ tests/ # Test suites - โ”œโ”€โ”€ unit/ - โ”œโ”€โ”€ integration/ - โ””โ”€โ”€ benchmarks/ -``` - ---- - -## [1.3.1] - 2025-03-23 - -### Added - -- **Full GoDoc coverage**: All exported constants, types, functions, and methods now include proper Go-style documentation comments. -- Added `make docs` command to validate documentation using `revive` and `go vet`. -- Improved test readability and structure. - -### Changed - -- **CI configuration refined**: - - Now runs only on `pull_request`, `pull_request_target`, and `push` to tags. - - Removed unnecessary runs on `push` to `main`. - - Still tests across `ubuntu-latest`, `macos-latest`, and `windows-latest`. - -- **Linting setup updated**: - - Deprecated linters (`deadcode`, `varcheck`, `structcheck`) removed. - - Migrated from `output.format` โ†’ `output.formats` in `golangci-lint` config. - - Replaced `run.skip-dirs` with `issues.exclude-dirs`. - -- Makefile updated: - - Added `docs` target for lint and vet. - - Improved log outputs for each target (build, test, clean, etc.). - -## [1.3.0] - 2025-03-23 - -### Added - -- Implemented full support for `Get*` and `Get*f` functions that return `(string, error)` for all message types. -- Added tests for `Get*` and `Get*f` variants to ensure correct error handling and output. -- Added `TestSetColorTableOverride` to verify custom ANSI color overrides. -- Added `TestLogOutput` to validate structured logging with message type tags (e.g., `[ERROR]`, `[INFO]`). - -### Changed - -- Split message function tests to differentiate between return (`Get*`) and no-return (`Success`, `Error`, etc.) implementations. -- Refactored test definitions for proper function signatures and removed invalid error assertions from no-return message methods. -- Improved test clarity and naming consistency across all test cases. - -## [1.2.0] - 2025-03-22 - -### Added - -- All message methods (`Success`, `Error`, `Info`, etc.) now return `(string, error)`. -- Introduced `ErrSilent` as a sentinel error for already displayed errors. -- Added fluent option methods for `Options` (e.g., `WithBold`, `WithoutColor`). -- Extended `Echo` to support `Callback` execution or `Exit`, depending on configuration. -- Full test coverage for all message types and formatting combinations. -- Added formatted versions of all message functions (e.g., `Successf`, `Errorf`, etc.). - -### Changed - -- `Echo` now accepts `*Options` instead of `Options` value. -- `Callback` and `Exit` are now mutually exclusive. -- Improved ANSI handling and color application. - -### Fixed - -- Fixed handling of `os.Stdout` and `ReadFrom` in test utilities. -- Fixed styling override conflicts between `NoStyle`, `Bold`, and `Italic`. - ---- - -## [1.1.0] - 2025-03-15 - -### Added - -- Introduced `OptionsDefault()` for easier initialization of options. -- Added support for `WithExit()` and `WithCallback()` ensuring mutual exclusivity: - - If `Callback` is set, `Exit` is automatically disabled. - - If `Exit` is enabled, `Callback` is removed. -- Implemented **table-driven tests** covering all functionalities. -- Added **log output** for each message type (`Success`, `Error`, `Warning`, etc.). - -### Changed - -- Improved `Echo()` function to respect `NoColor`, `NoStyle`, and `NoIcon` options correctly. -- Refactored `WithExit()` and `WithCallback()` to properly enforce behavior. -- Enhanced documentation and README to reflect new changes. - -### Fixed - -- Fixed issue where `Exit` and `Callback` could be set simultaneously. -- Resolved linter error (`errcheck`) by handling the return value of `buf.ReadFrom()` in tests. -- Improved test reliability and robustness. - ---- - -## [1.0.0] - Initial Release - -- Basic message styling (`Bold`, `Italic`, `NoColor`, `NoIcon`). -- Predefined message types (`Success`, `Error`, `Warning`, etc.). -- Initial unit tests with basic coverage. -- Custom color mappings using `SetColorTable()`. \ No newline at end of file +# Utify โ€“ Changelog + +Utify is a Go library for displaying styled and colorized messages in the terminal, with support for icons and flexible configurations. + +This changelog lists all notable changes in each release. +For full details, click a version number to view its dedicated file. + +--- + +## 1.x Releases + +- [1.4.13](changelogs/1.4.13.md) โ€” 2025โ€‘07โ€‘31 +- [1.4.12](changelogs/1.4.12.md) โ€” 2025โ€‘07โ€‘31 +- [1.4.11](changelogs/1.4.11.md) โ€” 2025โ€‘07โ€‘30 +- [1.4.10](changelogs/1.4.10.md) โ€” 2025โ€‘07โ€‘29 +- [1.4.9](changelogs/1.4.9.md) โ€” 2025โ€‘07โ€‘29 +- [1.4.8](changelogs/1.4.8.md) โ€” 2025โ€‘07โ€‘29 +- [1.4.7](changelogs/1.4.7.md) โ€” 2025โ€‘07โ€‘29 +- [1.4.6](changelogs/1.4.6.md) โ€” 2025โ€‘07โ€‘29 +- [1.4.5](changelogs/1.4.5.md) โ€” 2025โ€‘07โ€‘29 +- [1.4.4](changelogs/1.4.4.md) โ€” 2025โ€‘07โ€‘29 +- [1.4.3](changelogs/1.4.3.md) โ€” 2025โ€‘07โ€‘29 +- [1.4.2](changelogs/1.4.2.md) โ€” 2025โ€‘07โ€‘27 +- [1.4.1](changelogs/1.4.1.md) โ€” 2025โ€‘07โ€‘27 +- [1.4.0](changelogs/1.4.0.md) โ€” 2025โ€‘07โ€‘27 +- [1.3.1](changelogs/1.3.1.md) โ€” 2025โ€‘03โ€‘23 +- [1.3.0](changelogs/1.3.0.md) โ€” 2025โ€‘03โ€‘23 +- [1.2.0](changelogs/1.2.0.md) โ€” 2025โ€‘03โ€‘22 +- [1.1.0](changelogs/1.1.0.md) โ€” 2025โ€‘03โ€‘15 +- [1.0.0](changelogs/1.0.0.md) โ€” Initial release diff --git a/changelogs/1.0.0.md b/changelogs/1.0.0.md new file mode 100644 index 0000000..c245376 --- /dev/null +++ b/changelogs/1.0.0.md @@ -0,0 +1,6 @@ +## [1.0.0] - Initial Release + +- Basic message styling (`Bold`, `Italic`, `NoColor`, `NoIcon`). +- Predefined message types (`Success`, `Error`, `Warning`, etc.). +- Initial unit tests with basic coverage. +- Custom color mappings using `SetColorTable()`. \ No newline at end of file diff --git a/changelogs/1.1.0.md b/changelogs/1.1.0.md new file mode 100644 index 0000000..60bc8a2 --- /dev/null +++ b/changelogs/1.1.0.md @@ -0,0 +1,22 @@ +## [1.1.0] - 2025-03-15 + +### Added + +- Introduced `OptionsDefault()` for easier initialization of options. +- Added support for `WithExit()` and `WithCallback()` ensuring mutual exclusivity: + - If `Callback` is set, `Exit` is automatically disabled. + - If `Exit` is enabled, `Callback` is removed. +- Implemented **table-driven tests** covering all functionalities. +- Added **log output** for each message type (`Success`, `Error`, `Warning`, etc.). + +### Changed + +- Improved `Echo()` function to respect `NoColor`, `NoStyle`, and `NoIcon` options correctly. +- Refactored `WithExit()` and `WithCallback()` to properly enforce behavior. +- Enhanced documentation and README to reflect new changes. + +### Fixed + +- Fixed issue where `Exit` and `Callback` could be set simultaneously. +- Resolved linter error (`errcheck`) by handling the return value of `buf.ReadFrom()` in tests. +- Improved test reliability and robustness. \ No newline at end of file diff --git a/changelogs/1.2.0.md b/changelogs/1.2.0.md new file mode 100644 index 0000000..3f0d0d3 --- /dev/null +++ b/changelogs/1.2.0.md @@ -0,0 +1,21 @@ +## [1.2.0] - 2025-03-22 + +### Added + +- All message methods (`Success`, `Error`, `Info`, etc.) now return `(string, error)`. +- Introduced `ErrSilent` as a sentinel error for already displayed errors. +- Added fluent option methods for `Options` (e.g., `WithBold`, `WithoutColor`). +- Extended `Echo` to support `Callback` execution or `Exit`, depending on configuration. +- Full test coverage for all message types and formatting combinations. +- Added formatted versions of all message functions (e.g., `Successf`, `Errorf`, etc.). + +### Changed + +- `Echo` now accepts `*Options` instead of `Options` value. +- `Callback` and `Exit` are now mutually exclusive. +- Improved ANSI handling and color application. + +### Fixed + +- Fixed handling of `os.Stdout` and `ReadFrom` in test utilities. +- Fixed styling override conflicts between `NoStyle`, `Bold`, and `Italic`. \ No newline at end of file diff --git a/changelogs/1.3.0.md b/changelogs/1.3.0.md new file mode 100644 index 0000000..6f0f98b --- /dev/null +++ b/changelogs/1.3.0.md @@ -0,0 +1,14 @@ +## [1.3.0] - 2025-03-23 + +### Added + +- Implemented full support for `Get*` and `Get*f` functions that return `(string, error)` for all message types. +- Added tests for `Get*` and `Get*f` variants to ensure correct error handling and output. +- Added `TestSetColorTableOverride` to verify custom ANSI color overrides. +- Added `TestLogOutput` to validate structured logging with message type tags (e.g., `[ERROR]`, `[INFO]`). + +### Changed + +- Split message function tests to differentiate between return (`Get*`) and no-return (`Success`, `Error`, etc.) implementations. +- Refactored test definitions for proper function signatures and removed invalid error assertions from no-return message methods. +- Improved test clarity and naming consistency across all test cases. \ No newline at end of file diff --git a/changelogs/1.3.1.md b/changelogs/1.3.1.md new file mode 100644 index 0000000..7efc128 --- /dev/null +++ b/changelogs/1.3.1.md @@ -0,0 +1,23 @@ +## [1.3.1] - 2025-03-23 + +### Added + +- **Full GoDoc coverage**: All exported constants, types, functions, and methods now include proper Go-style documentation comments. +- Added `make docs` command to validate documentation using `revive` and `go vet`. +- Improved test readability and structure. + +### Changed + +- **CI configuration refined**: + - Now runs only on `pull_request`, `pull_request_target`, and `push` to tags. + - Removed unnecessary runs on `push` to `main`. + - Still tests across `ubuntu-latest`, `macos-latest`, and `windows-latest`. + +- **Linting setup updated**: + - Deprecated linters (`deadcode`, `varcheck`, `structcheck`) removed. + - Migrated from `output.format` โ†’ `output.formats` in `golangci-lint` config. + - Replaced `run.skip-dirs` with `issues.exclude-dirs`. + +- Makefile updated: + - Added `docs` target for lint and vet. + - Improved log outputs for each target (build, test, clean, etc.). \ No newline at end of file diff --git a/changelogs/1.4.0.md b/changelogs/1.4.0.md new file mode 100644 index 0000000..179670d --- /dev/null +++ b/changelogs/1.4.0.md @@ -0,0 +1,102 @@ +## [1.4.0] - 2025-07-27 + +### ๐Ÿš€ Major Features + +- **Modular Architecture**: Complete restructure from single-file to proper Go package organization: + - `pkg/colors/`: ANSI color constants and management + - `pkg/messages/`: Message types and definitions + - `pkg/options/`: Options struct with fluent API + - `pkg/formatter/`: Core formatting logic + - `pkg/logger/`: Structured JSON logging system + - `internal/tests/`: Test utilities + - Organized test structure: unit, integration, and benchmarks + +- **Structured JSON Logging**: Full logging system with configurable targets: + - Default path: `/var/log/{binary_name}.log` (with fallback to current directory) + - JSON format with timestamp, level, message, type, and binary name + - Configurable log target: `SetLogTarget(path)` + - Enable/disable logging: `SetLoggingEnabled(bool)` + - Log file handle management: `CloseLogger()` + +- **Log-Only Functions**: New API for logging without stdout output: + - `LogSuccess()`, `LogError()`, `LogWarning()`, `LogInfo()`, `LogDebug()`, `LogCritical()` + - `LogDelete()`, `LogUpdate()`, `LogInstall()`, `LogUpgrade()`, `LogEdit()`, `LogNew()` + - `LogDownload()`, `LogUpload()`, `LogSync()`, `LogSearch()` + - Formatted versions: `LogSuccessf()`, `LogErrorf()`, etc. + +- **Icon System**: Smart icon display with Nerd Font support: + - Automatic Nerd Font detection via environment variables (`TERM_PROGRAM`, `NERD_FONT_DETECTED`) + - Fallback to regular Unicode icons when Nerd Fonts are not available + - User control: `ForceNerdFont()`, `ForceRegularIcons()`, `DisableIcons()` + - Integration with existing options: `WithIcon()`, `WithoutIcon()` + +### ๐Ÿ”ง Breaking Changes + +- **Package Name**: Changed from `github.com/jonatas-sas/utify` to `github.com/jsas4coding/utify` +- **Go Version**: Bumped to Go 1.24.5 +- **Test Structure**: Moved `internal/testutil/` to `internal/tests/` with package name change + +### โœจ Improvements + +- **Fixed Double Message Bug**: Eliminated duplicate message printing +- **Comprehensive Testing**: Added unit tests, integration tests, and benchmarks +- **Better Examples**: Organized examples into separate directories with dedicated demos +- **Enhanced Documentation**: Updated CLAUDE.md with new architecture details +- **Lint Configuration**: Fixed and simplified revive configuration + +### ๐Ÿ“ฆ New API Functions + +```go +// Logging configuration +SetLogTarget(path string) error +GetLogTarget() string +SetLoggingEnabled(enabled bool) +IsLoggingEnabled() bool +CloseLogger() + +// Log-only functions (no stdout output) +LogSuccess(text string) +LogError(text string) +// ... and all other message types + +// Formatted log-only functions +LogSuccessf(text string, args ...any) +LogErrorf(text string, args ...any) +// ... and all other message types + +// Icon control functions +ForceNerdFont() +ForceRegularIcons() +DisableIcons() +GetIconType() IconType +SetIconType(IconType) +``` + +### ๐Ÿงช Testing + +- **Unit Tests**: Complete coverage for all packages +- **Integration Tests**: API compatibility and functionality verification +- **Benchmarks**: Performance testing for all core functions +- **Test Utilities**: Centralized test helpers for output capture + +### ๐Ÿ“ Project Structure + +``` +utify/ +โ”œโ”€โ”€ pkg/ # Core packages +โ”‚ โ”œโ”€โ”€ colors/ # ANSI colors +โ”‚ โ”œโ”€โ”€ messages/ # Message types +โ”‚ โ”œโ”€โ”€ options/ # Configuration +โ”‚ โ”œโ”€โ”€ formatter/ # Output formatting +โ”‚ โ””โ”€โ”€ logger/ # JSON logging +โ”œโ”€โ”€ internal/tests/ # Test utilities +โ”œโ”€โ”€ examples/ # Usage examples +โ”‚ โ”œโ”€โ”€ basic/ +โ”‚ โ”œโ”€โ”€ colors/ +โ”‚ โ”œโ”€โ”€ callbacks/ +โ”‚ โ””โ”€โ”€ logging-demo/ +โ””โ”€โ”€ tests/ # Test suites + โ”œโ”€โ”€ unit/ + โ”œโ”€โ”€ integration/ + โ””โ”€โ”€ benchmarks/ +``` \ No newline at end of file diff --git a/changelogs/1.4.1.md b/changelogs/1.4.1.md new file mode 100644 index 0000000..87e8fe7 --- /dev/null +++ b/changelogs/1.4.1.md @@ -0,0 +1,14 @@ +## [1.4.1] - 2025-07-27 + +### ๐Ÿ”ง Bug Fixes + +- **Lint Compliance**: Fixed all linting issues for clean code quality + - Fixed 7 `errcheck` violations by properly handling file close operations + - Fixed 1 `ineffassign` violation by removing unused variable assignment + - Updated golangci-lint configuration for modern standards + +### ๐Ÿ—๏ธ Code Quality + +- **Error Handling**: Improved error handling in logger cleanup operations +- **Test Robustness**: Enhanced test cleanup to properly ignore expected errors +- **Linting**: Achieved 0 lint issues across all linters (errcheck, govet, gosimple, staticcheck, unused, revive, gofmt, goimports). \ No newline at end of file diff --git a/changelogs/1.4.10.md b/changelogs/1.4.10.md new file mode 100644 index 0000000..4056a21 --- /dev/null +++ b/changelogs/1.4.10.md @@ -0,0 +1,19 @@ +## [1.4.10] - 2025-07-29 + +### ๐Ÿงช Testing + +- **Refactored tests for `utify.go`**: + - Split the old `TestAllOutputFunctions` into modular **table-driven tests** for: + - Direct output functions (`Success`, `Error`, `Info`, etc.). + - Formatted output functions (`Successf`, `Errorf`, etc.). + - Getter functions (`Get*`). + - Log-only functions (`Log*`). + - Configuration functions (`SetColorTable`, `SetLogTarget`, `SetLoggingEnabled`, `ForceNerdFont`, etc.). + - Added new tests for **`internal/tests/util.go`** (`CaptureOutput` and `CaptureLogOutput`). +- **Reduced cyclomatic complexity** of tests to comply with `gocyclo`. +- **Package names for tests standardized** to `unit` across the test suite. + +### ๐Ÿ›  Maintenance + +- **Excluded `examples/` folder from coverage** (via `codecov.yml`). +- Unified test style across the repository for better maintainability. \ No newline at end of file diff --git a/changelogs/1.4.11.md b/changelogs/1.4.11.md new file mode 100644 index 0000000..85099c3 --- /dev/null +++ b/changelogs/1.4.11.md @@ -0,0 +1,11 @@ +## [1.4.11] - 2025-07-30 + +### ๐Ÿงช Testing + +- **Expanded coverage for `utify.go`**: + - Added **table-driven tests** for all formatted getter functions (`Get*f`), covering previously untested methods like `GetSearchf`, `GetUploadf`, etc. + - Added **table-driven tests** for all formatted log-only functions (`Log*f`), covering previously untested methods like `LogSearchf`, `LogUploadf`, etc. + - Introduced tests for **silent mode (`ErrSilent`)** to ensure correct behavior when output is suppressed. + - Added negative tests for **`SetLogTarget`** with invalid paths to validate error handling. +- **Improved test modularity** by splitting new cases into separate blocks for clarity. +- **Target coverage increase**: Pushed coverage for `utify.go` close to 100%. \ No newline at end of file diff --git a/changelogs/1.4.12.md b/changelogs/1.4.12.md new file mode 100644 index 0000000..eac7593 --- /dev/null +++ b/changelogs/1.4.12.md @@ -0,0 +1,16 @@ +## [1.4.12] - 2025-07-31 + +### ๐Ÿš€ Features + +- **Improved Test Suite**: Enhanced test coverage for the `icons` and `logger` packages, ensuring greater reliability and robustness. +- **Test Artifacts Directory**: All files created during tests are now stored in the `tests/data` directory, keeping the project root clean. + +### ๐Ÿ”ง Fixes + +- **Stricter Log Target Handling**: The `SetLogTarget` function now returns an error if the specified log path is not writable, making its behavior more predictable. +- **Improved Test Reliability**: Fixed an issue in the `TestNerdFontDetectionEnvVar` test by exposing the `icons.Init()` function, allowing the test to re-trigger icon detection after modifying environment variables. + +### ๐Ÿ“š Documentation + +- **Updated README.md**: The `README.md` file has been updated to include all the latest features, a new section explaining the example applications, and the "What's New" section has been moved to the beginning of the file for better visibility. +- **Added SECURITY.md**: A `SECURITY.md` file has been added to the `.github` directory, providing clear guidelines for reporting security vulnerabilities. \ No newline at end of file diff --git a/changelogs/1.4.13.md b/changelogs/1.4.13.md new file mode 100644 index 0000000..bfcb391 --- /dev/null +++ b/changelogs/1.4.13.md @@ -0,0 +1,16 @@ +# [1.4.13] - 2025-07-31 + +### ๐Ÿ“š Documentation + +- **Changelog Restructure:** + - Split the monolithic `CHANGELOG.md` into individual files under `changelogs/`, one per version. + - Updated the main `CHANGELOG.md` to serve as an index linking to each version. + - Added a short project description at the top of the main changelog for better context. + +### ๐Ÿ›  CI/CD + +- **Release Workflow Update:** + - Release body now pulls from the dedicated version changelog file (`changelogs/{version}.md`). + - Workflow now fails if the changelog file for the tagged version does not exist or is missing from the index. + - Added coverage enforcement: pipeline fails if total coverage drops below **90%**. + - Generated a Markdown-formatted coverage report as a build artifact. diff --git a/changelogs/1.4.2.md b/changelogs/1.4.2.md new file mode 100644 index 0000000..60e081b --- /dev/null +++ b/changelogs/1.4.2.md @@ -0,0 +1,31 @@ +## [1.4.2] - 2025-07-27 + +### โšก Performance & Code Quality + +- **Code Refactoring**: Reduced cyclomatic complexity for better maintainability + - Refactored `detectNerdFont()` function: Split complex logic into 4 focused functions + - Refactored `Echo()` function: Split formatting logic into 6 specialized functions + - All functions now have complexity โ‰ค 9 (under threshold of 10) + +### ๐Ÿ”ง CI/CD Improvements + +- **Enhanced Workflow Configuration**: Improved GitHub Actions setup + - **Go Version Management**: All workflows now read Go version from `go.mod` file + - **Smart CI Triggering**: Optimized to avoid duplicate runs while ensuring comprehensive coverage + - Runs on: pull requests to main, pushes to main, and tag pushes (releases) + - Codecov uploads on main branch updates and releases + - **Updated Codecov Integration**: Upgraded to `codecov/codecov-action@v5` with better error handling + - **Removed Problematic Dependencies**: Fixed security scanning by removing non-existent packages + +### ๐Ÿ—๏ธ Code Organization + +- **Better Separation of Concerns**: Functions now follow single responsibility principle +- **Improved Readability**: Complex logic broken down into smaller, focused functions +- **Enhanced Maintainability**: Changes can be made to specific functionality without affecting others + +### ๐Ÿงช Quality Assurance + +- **Cyclomatic Complexity**: All functions now pass complexity analysis (gocyclo -over 10) +- **Static Analysis**: Clean staticcheck results +- **Comprehensive Testing**: All unit and integration tests continue to pass +- **Lint Compliance**: Maintains 0 lint issues across all linters. \ No newline at end of file diff --git a/changelogs/1.4.3.md b/changelogs/1.4.3.md new file mode 100644 index 0000000..e8e01a4 --- /dev/null +++ b/changelogs/1.4.3.md @@ -0,0 +1,19 @@ +## [1.4.3] - 2025-07-29 + +### ๐Ÿš€ Features & Improvements + +- **CI/CD Pipeline Enhancements**: + - Unified workflows into `cicd.yml` combining CI, quality checks, examples build, and release automation. + - Added build process for `examples/` with automatic artifact upload for quick testing. + - Integrated Codecov coverage reports for main branch pushes. + - Separated unit, integration, and benchmark tests with clear visibility. + - Automated Go module publishing to `proxy.golang.org` after tagged releases. + +- **Release Automation**: + - Added automatic changelog generation using `git-chglog`. + - GitHub Releases now include compiled example binaries. + +### ๐Ÿงช Quality & Security + +- **Enhanced Quality Checks**: Strengthened static analysis with `golangci-lint` and cyclomatic complexity validation. +- **Security**: Removed outdated dependencies in workflows and improved token usage for uploads. \ No newline at end of file diff --git a/changelogs/1.4.4.md b/changelogs/1.4.4.md new file mode 100644 index 0000000..c889dfb --- /dev/null +++ b/changelogs/1.4.4.md @@ -0,0 +1,6 @@ +## [1.4.4] - 2025-07-29 + +### ๐Ÿ”ง Bug Fixes + +- **CI/CD:** Release workflow now updates existing GitHub releases instead of creating duplicates. +- **Artifacts:** Ensures latest built examples are attached when updating a release. \ No newline at end of file diff --git a/changelogs/1.4.5.md b/changelogs/1.4.5.md new file mode 100644 index 0000000..05c39ca --- /dev/null +++ b/changelogs/1.4.5.md @@ -0,0 +1,5 @@ +## [1.4.5] - 2025-07-29 + +### ๐Ÿ”ง Fixes + +- **Permissions:** Added `permissions: contents: write` to enable release updates. \ No newline at end of file diff --git a/changelogs/1.4.6.md b/changelogs/1.4.6.md new file mode 100644 index 0000000..cc108f0 --- /dev/null +++ b/changelogs/1.4.6.md @@ -0,0 +1,6 @@ +## [1.4.6] - 2025-07-29 + +### ๐Ÿ”ง Fixes + +- **CI/CD:** Corrected `release` job to export the version as an output for dependent jobs. +- **Release Updates:** Ensured the GitHub release step can update existing releases with new artifacts. \ No newline at end of file diff --git a/changelogs/1.4.7.md b/changelogs/1.4.7.md new file mode 100644 index 0000000..795c1bc --- /dev/null +++ b/changelogs/1.4.7.md @@ -0,0 +1,7 @@ +## [1.4.7] - 2025-07-29 + +### ๐Ÿ”ง Fixes & Improvements + +- **CI/CD:** Updated Codecov upload step to use `codecov/codecov-action@v5` with explicit `slug` and `token` for reliable coverage reporting. +- **Release Automation:** Enhanced release workflow to extract the correct changelog section automatically and set formatted release titles. +- **Caching:** Updated cache keys across jobs to include `github.sha`, ensuring cache invalidation on code changes. \ No newline at end of file diff --git a/changelogs/1.4.8.md b/changelogs/1.4.8.md new file mode 100644 index 0000000..f525ca1 --- /dev/null +++ b/changelogs/1.4.8.md @@ -0,0 +1,9 @@ +## [1.4.8] - 2025-07-29 + +### ๐Ÿ”’ Security + +- **Added CodeQL Analysis:** Introduced automated CodeQL scans for Go, running on pushes, pull requests, and weekly schedules. + +### ๐Ÿงช Testing + +- **Enhanced Coverage:** Expanded coverage reporting to include all Go packages and added validation to prevent zero-coverage reports. \ No newline at end of file diff --git a/changelogs/1.4.9.md b/changelogs/1.4.9.md new file mode 100644 index 0000000..ce5ce52 --- /dev/null +++ b/changelogs/1.4.9.md @@ -0,0 +1,22 @@ +## [1.4.9] - 2025-07-29 + +### ๐Ÿงช Testing + +- Added **new unit tests** for `utify.go`, improving coverage and reliability. +- Expanded tests to cover **logging-only functions** and **"Get" functions**. + +### ๐Ÿ“š Documentation + +- **Improved doccomments** in `utify.go`: + - Added comprehensive package-level documentation. + - Documented customization features for colors, icons, and logging. + - Clarified usage examples for: + - Direct output functions (e.g., `utify.Success()`) + - Formatted functions (e.g., `utify.Infof()`) + - Getters (e.g., `utify.GetSuccess()`) + - Logging-only functions (e.g., `utify.LogInfo()`) + +### ๐Ÿ›  Maintenance + +- Minor refactoring for **consistency across all message functions**. +- Updated **aliases** for backward compatibility (`MessageType`, `Options`). \ No newline at end of file From e9dcdd3a241d9cbf448d4870e8202067fa45ccac Mon Sep 17 00:00:00 2001 From: Jonatas Sas Date: Thu, 31 Jul 2025 11:28:45 -0300 Subject: [PATCH 2/8] Coverage Updates --- .github/workflows/utify.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/utify.yml b/.github/workflows/utify.yml index c89ed80..cdacfa4 100644 --- a/.github/workflows/utify.yml +++ b/.github/workflows/utify.yml @@ -39,8 +39,10 @@ jobs: else git diff --exit-code go.mod fi - - name: Run tests with full coverage - run: go test -v -race -timeout=5m -coverpkg=./... -coverprofile=coverage.out ./... + - name: Run tests with full coverage (excluding examples and tests) + run: | + PKGS=$(go list ./... | grep -vE '^github.com/jsas4coding/utify/examples|^github.com/jsas4coding/utify/tests') + go test -v -race -timeout=5m -coverpkg=$(echo $PKGS | tr '\n' ',') -coverprofile=coverage.out ./... - name: Run integration tests run: go test -v -race -timeout=10m -coverpkg=./... ./tests/integration/... - name: Run benchmarks From eff4e160ee4f3b3da98b410c431c6e75c201f8d8 Mon Sep 17 00:00:00 2001 From: Jonatas Sas Date: Thu, 31 Jul 2025 11:30:47 -0300 Subject: [PATCH 3/8] Fixes --- .github/workflows/utify.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/utify.yml b/.github/workflows/utify.yml index cdacfa4..1873048 100644 --- a/.github/workflows/utify.yml +++ b/.github/workflows/utify.yml @@ -15,7 +15,7 @@ on: jobs: validate: - name: Quick Validation + name: Validation runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -41,10 +41,11 @@ jobs: fi - name: Run tests with full coverage (excluding examples and tests) run: | - PKGS=$(go list ./... | grep -vE '^github.com/jsas4coding/utify/examples|^github.com/jsas4coding/utify/tests') - go test -v -race -timeout=5m -coverpkg=$(echo $PKGS | tr '\n' ',') -coverprofile=coverage.out ./... + PKGS=$(go list ./... | grep -vE '/examples|/tests') + echo "Packages for coverage:" $PKGS + go test -v -race -timeout=5m -coverpkg=$(echo $PKGS | tr ' ' ',') -coverprofile=coverage.out $PKGS - name: Run integration tests - run: go test -v -race -timeout=10m -coverpkg=./... ./tests/integration/... + run: go test -v -race -timeout=10m ./tests/integration/... - name: Run benchmarks run: go test -bench=. -benchtime=5s ./tests/benchmarks/... - name: Fail if coverage is below 90% @@ -177,4 +178,3 @@ jobs: GOPROXY=proxy.golang.org go list -m github.com/jsas4coding/utify@${VERSION} - name: Confirm publication run: echo "Release ${{ needs.release.outputs.version }} published successfully!" - From 1711292c1b3bcae122504becccf5a7c491762507 Mon Sep 17 00:00:00 2001 From: Jonatas Sas Date: Thu, 31 Jul 2025 11:36:04 -0300 Subject: [PATCH 4/8] Coverage Fixes --- .github/workflows/utify.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/utify.yml b/.github/workflows/utify.yml index 1873048..b6e9750 100644 --- a/.github/workflows/utify.yml +++ b/.github/workflows/utify.yml @@ -43,13 +43,14 @@ jobs: run: | PKGS=$(go list ./... | grep -vE '/examples|/tests') echo "Packages for coverage:" $PKGS - go test -v -race -timeout=5m -coverpkg=$(echo $PKGS | tr ' ' ',') -coverprofile=coverage.out $PKGS + go test -v -race -timeout=5m -coverpkg=$(echo $PKGS | paste -sd, -) -coverprofile=coverage.out $PKGS - name: Run integration tests run: go test -v -race -timeout=10m ./tests/integration/... - name: Run benchmarks run: go test -bench=. -benchtime=5s ./tests/benchmarks/... - name: Fail if coverage is below 90% run: | + go tool cover -func=coverage.out COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//') echo "Total coverage: $COVERAGE%" if (( $(echo "$COVERAGE < 90" | bc -l) )); then @@ -101,7 +102,7 @@ jobs: gocyclo -over 15 . release: - name: Validate & Prepare Release + name: Release Validation & Preparation runs-on: ubuntu-latest needs: validate if: startsWith(github.ref, 'refs/tags/v') From 3e344c3212b275128b76d9751742bd48167fa5dd Mon Sep 17 00:00:00 2001 From: Jonatas Sas Date: Thu, 31 Jul 2025 11:41:17 -0300 Subject: [PATCH 5/8] Coverage tests --- .github/workflows/utify.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/utify.yml b/.github/workflows/utify.yml index b6e9750..fbfbd31 100644 --- a/.github/workflows/utify.yml +++ b/.github/workflows/utify.yml @@ -39,13 +39,11 @@ jobs: else git diff --exit-code go.mod fi - - name: Run tests with full coverage (excluding examples and tests) + - name: Run tests with full coverage (unit + integration) run: | - PKGS=$(go list ./... | grep -vE '/examples|/tests') + PKGS=$(go list ./... | grep -vE '/examples') echo "Packages for coverage:" $PKGS - go test -v -race -timeout=5m -coverpkg=$(echo $PKGS | paste -sd, -) -coverprofile=coverage.out $PKGS - - name: Run integration tests - run: go test -v -race -timeout=10m ./tests/integration/... + go test -v -race -timeout=10m -coverpkg=$(echo $PKGS | paste -sd, -) -coverprofile=coverage.out ./tests/unit/... ./tests/integration/... - name: Run benchmarks run: go test -bench=. -benchtime=5s ./tests/benchmarks/... - name: Fail if coverage is below 90% @@ -179,3 +177,4 @@ jobs: GOPROXY=proxy.golang.org go list -m github.com/jsas4coding/utify@${VERSION} - name: Confirm publication run: echo "Release ${{ needs.release.outputs.version }} published successfully!" + From c0e217ca50c1dadffdae793aaed5deedf794d6b6 Mon Sep 17 00:00:00 2001 From: Jonatas Sas Date: Thu, 31 Jul 2025 11:48:36 -0300 Subject: [PATCH 6/8] Pipeline fixes --- .github/workflows/utify.yml | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/.github/workflows/utify.yml b/.github/workflows/utify.yml index fbfbd31..21e453b 100644 --- a/.github/workflows/utify.yml +++ b/.github/workflows/utify.yml @@ -39,11 +39,11 @@ jobs: else git diff --exit-code go.mod fi - - name: Run tests with full coverage (unit + integration) + - name: Run tests with full coverage (all packages + tests) run: | PKGS=$(go list ./... | grep -vE '/examples') echo "Packages for coverage:" $PKGS - go test -v -race -timeout=10m -coverpkg=$(echo $PKGS | paste -sd, -) -coverprofile=coverage.out ./tests/unit/... ./tests/integration/... + go test -v -race -timeout=10m -coverpkg=$(echo $PKGS | paste -sd, -) -coverprofile=coverage.out $PKGS ./tests/unit/... ./tests/integration/... - name: Run benchmarks run: go test -bench=. -benchtime=5s ./tests/benchmarks/... - name: Fail if coverage is below 90% @@ -54,18 +54,6 @@ jobs: if (( $(echo "$COVERAGE < 90" | bc -l) )); then echo "Coverage below 90% - failing." && exit 1 fi - - name: Generate coverage report (Markdown) - run: | - go tool cover -func=coverage.out | tee coverage_report.txt - echo "# Coverage Report" > coverage_report.md - echo '```' >> coverage_report.md - cat coverage_report.txt >> coverage_report.md - echo '```' >> coverage_report.md - - name: Upload coverage report - uses: actions/upload-artifact@v4 - with: - name: coverage-report - path: coverage_report.md - name: Upload coverage reports to Codecov if: github.ref == 'refs/heads/main' uses: codecov/codecov-action@v5 @@ -142,6 +130,20 @@ jobs: go build -o "dist/examples/$name" "$dir" done + - name: Generate coverage report (Markdown) + run: | + go tool cover -func=coverage.out | tee coverage_report.txt + echo "# Coverage Report" > coverage_report.md + echo '```' >> coverage_report.md + cat coverage_report.txt >> coverage_report.md + echo '```' >> coverage_report.md + + - name: Upload coverage report + uses: actions/upload-artifact@v4 + with: + name: coverage-report + path: coverage_report.md + - name: Create or Update GitHub Release uses: softprops/action-gh-release@v2 with: @@ -177,4 +179,3 @@ jobs: GOPROXY=proxy.golang.org go list -m github.com/jsas4coding/utify@${VERSION} - name: Confirm publication run: echo "Release ${{ needs.release.outputs.version }} published successfully!" - From 4cef5e05e605f12fcfe8b24f1eb6cc3ea9fb2023 Mon Sep 17 00:00:00 2001 From: Jonatas Sas Date: Thu, 31 Jul 2025 12:11:33 -0300 Subject: [PATCH 7/8] Prepare for test structure changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Restructured test directories - Updated GitHub Actions workflow - Updated Makefile for new test paths - Improved test coverage and reporting ๐Ÿ”ง Refactoring in preparation for v1.4.13 --- .github/workflows/utify.yml | 4 +- .gitignore | 2 + Makefile | 8 +- changelogs/1.4.13.md | 24 ++ {tests/unit => internal/tests}/util_test.go | 8 +- {tests/unit => pkg/colors}/colors_test.go | 22 +- .../unit => pkg/formatter}/formatter_test.go | 21 +- {tests/unit => pkg/icons}/icons_test.go | 87 ++++--- {tests/unit => pkg/logger}/logger_test.go | 83 ++++-- {tests/unit => pkg/messages}/messages_test.go | 37 ++- {tests/unit => pkg/options}/options_test.go | 45 +++- tests/unit/utify_test.go | 237 ------------------ utify_test.go | 235 +++++++++++++++++ 13 files changed, 452 insertions(+), 361 deletions(-) rename {tests/unit => internal/tests}/util_test.go (76%) rename {tests/unit => pkg/colors}/colors_test.go (64%) rename {tests/unit => pkg/formatter}/formatter_test.go (83%) rename {tests/unit => pkg/icons}/icons_test.go (55%) rename {tests/unit => pkg/logger}/logger_test.go (63%) rename {tests/unit => pkg/messages}/messages_test.go (56%) rename {tests/unit => pkg/options}/options_test.go (70%) delete mode 100644 tests/unit/utify_test.go create mode 100644 utify_test.go diff --git a/.github/workflows/utify.yml b/.github/workflows/utify.yml index 21e453b..7116e4a 100644 --- a/.github/workflows/utify.yml +++ b/.github/workflows/utify.yml @@ -41,9 +41,9 @@ jobs: fi - name: Run tests with full coverage (all packages + tests) run: | - PKGS=$(go list ./... | grep -vE '/examples') + PKGS=$(go list ./pkg/... ./internal/... | grep -vE '/examples') echo "Packages for coverage:" $PKGS - go test -v -race -timeout=10m -coverpkg=$(echo $PKGS | paste -sd, -) -coverprofile=coverage.out $PKGS ./tests/unit/... ./tests/integration/... + go test -v -race -timeout=10m -coverpkg=$(echo $PKGS | paste -sd, -) -coverprofile=coverage.out ./pkg/... ./internal/... ./tests/... - name: Run benchmarks run: go test -bench=. -benchtime=5s ./tests/benchmarks/... - name: Fail if coverage is below 90% diff --git a/.gitignore b/.gitignore index c34ac2c..d6628ab 100644 --- a/.gitignore +++ b/.gitignore @@ -94,3 +94,5 @@ e2e-sandbox/ *.out coverage.html *coverage.html + +# No specific changes needed for examples diff --git a/Makefile b/Makefile index 5f95b8c..f672b3c 100644 --- a/Makefile +++ b/Makefile @@ -32,12 +32,12 @@ run: build # Run tests with verbose output test: @echo "๐Ÿงช Running tests..." - @go test -v ./tests/... + @go test -v ./tests/... ./pkg/... ./internal/... # Run unit tests only test-unit: @echo "๐Ÿงช Running unit tests..." - @go test -v ./tests/unit/... + @go test -v ./pkg/*/tests.go ./pkg/*/tests/*.go # Run integration tests only test-integration: @@ -52,13 +52,13 @@ bench: # Run tests with coverage and generate report coverage: @echo "๐Ÿ“Š Running tests with coverage..." - @go test -coverprofile=coverage.out ./tests/... + @go test -coverprofile=coverage.out ./tests/... ./pkg/... ./internal/... -cover -coverpkg=./pkg/...,./internal/... @go tool cover -func=coverage.out # Generate HTML coverage report coverage-html: @echo "๐Ÿ“Š Generating HTML coverage report..." - @go test -coverprofile=coverage.out ./tests/... + @go test -coverprofile=coverage.out ./tests/... ./pkg/... ./internal/... -cover -coverpkg=./pkg/...,./internal/... @go tool cover -html=coverage.out -o coverage.html @echo "โœ… Coverage report generated: coverage.html" diff --git a/changelogs/1.4.13.md b/changelogs/1.4.13.md index bfcb391..16c1f4d 100644 --- a/changelogs/1.4.13.md +++ b/changelogs/1.4.13.md @@ -14,3 +14,27 @@ - Workflow now fails if the changelog file for the tagged version does not exist or is missing from the index. - Added coverage enforcement: pipeline fails if total coverage drops below **90%**. - Generated a Markdown-formatted coverage report as a build artifact. + +### ๐Ÿงช Testing + +- **Test Structure Improvements:** + - Restructured unit tests to be located in their corresponding package directories. + - Moved tests from `tests/unit/` to respective package directories (e.g., `pkg/colors/colors_test.go`). + - Improved test coverage across multiple packages: + - `pkg/options`: Achieved 100% test coverage + - `pkg/logger`: Increased test coverage to 82.5% + - Added more comprehensive test cases for edge cases and different code paths. + +### ๐Ÿ”ง Project Structure + +- **Repository Organization:** + - Updated Makefile to exclude examples directory from test coverage. + - Adjusted test configuration to run tests from `tests/`, `pkg/`, and `internal/` directories. + - Added `.gitignore` configuration for better repository management. + +### ๐Ÿ”ฌ Code Quality + +- **Continuous Improvement:** + - Refined error handling and test coverage. + - Improved icon and logging functionality test cases. + - Enhanced package-level test suites to provide more robust code verification. \ No newline at end of file diff --git a/tests/unit/util_test.go b/internal/tests/util_test.go similarity index 76% rename from tests/unit/util_test.go rename to internal/tests/util_test.go index 0295043..8647fe1 100644 --- a/tests/unit/util_test.go +++ b/internal/tests/util_test.go @@ -1,17 +1,15 @@ -package unit +package tests import ( "fmt" "log" "strings" "testing" - - "github.com/jsas4coding/utify/internal/tests" ) func TestCaptureOutput(t *testing.T) { expected := "Hello, stdout!" - output := tests.CaptureOutput(func() { + output := CaptureOutput(func() { fmt.Print(expected) }) if !strings.Contains(output, expected) { @@ -21,7 +19,7 @@ func TestCaptureOutput(t *testing.T) { func TestCaptureLogOutput(t *testing.T) { expected := "Hello, log!" - output := tests.CaptureLogOutput(func() { + output := CaptureLogOutput(func() { log.Print(expected) }) if !strings.Contains(output, expected) { diff --git a/tests/unit/colors_test.go b/pkg/colors/colors_test.go similarity index 64% rename from tests/unit/colors_test.go rename to pkg/colors/colors_test.go index 03f7f27..31606ce 100644 --- a/tests/unit/colors_test.go +++ b/pkg/colors/colors_test.go @@ -1,22 +1,20 @@ -package unit +package colors import ( "testing" - - "github.com/jsas4coding/utify/pkg/colors" ) func TestSetColorTable(t *testing.T) { - colors.ClearUserColors() + ClearUserColors() customColors := map[string]string{ "success": "\033[95m", // Purple "error": "\033[96m", // Cyan } - colors.SetColorTable(customColors) + SetColorTable(customColors) - color, exists := colors.GetUserColor("success") + color, exists := GetUserColor("success") if !exists { t.Error("Expected success color to exist in user colors") } @@ -24,7 +22,7 @@ func TestSetColorTable(t *testing.T) { t.Errorf("Expected success color to be %q, got %q", "\033[95m", color) } - color, exists = colors.GetUserColor("error") + color, exists = GetUserColor("error") if !exists { t.Error("Expected error color to exist in user colors") } @@ -34,19 +32,19 @@ func TestSetColorTable(t *testing.T) { } func TestGetUserColorNotExists(t *testing.T) { - colors.ClearUserColors() + ClearUserColors() - _, exists := colors.GetUserColor("nonexistent") + _, exists := GetUserColor("nonexistent") if exists { t.Error("Expected nonexistent color to not exist") } } func TestClearUserColors(t *testing.T) { - colors.SetColorTable(map[string]string{"test": "value"}) - colors.ClearUserColors() + SetColorTable(map[string]string{"test": "value"}) + ClearUserColors() - _, exists := colors.GetUserColor("test") + _, exists := GetUserColor("test") if exists { t.Error("Expected user colors to be cleared") } diff --git a/tests/unit/formatter_test.go b/pkg/formatter/formatter_test.go similarity index 83% rename from tests/unit/formatter_test.go rename to pkg/formatter/formatter_test.go index 536f849..f753d32 100644 --- a/tests/unit/formatter_test.go +++ b/pkg/formatter/formatter_test.go @@ -1,4 +1,4 @@ -package unit +package formatter import ( "errors" @@ -7,7 +7,6 @@ import ( testutil "github.com/jsas4coding/utify/internal/tests" "github.com/jsas4coding/utify/pkg/colors" - "github.com/jsas4coding/utify/pkg/formatter" "github.com/jsas4coding/utify/pkg/messages" "github.com/jsas4coding/utify/pkg/options" ) @@ -31,15 +30,15 @@ func TestEcho(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { output := testutil.CaptureOutput(func() { - _, _ = formatter.Echo(tt.msgType, tt.text, tt.opts) + _, _ = Echo(tt.msgType, tt.text, tt.opts) }) if !strings.Contains(output, tt.text) { t.Errorf("Expected output to contain %q, got %q", tt.text, output) } - _, err := formatter.Echo(tt.msgType, tt.text, tt.opts) - if tt.shouldError && !errors.Is(err, formatter.ErrSilent) { + _, err := Echo(tt.msgType, tt.text, tt.opts) + if tt.shouldError && !errors.Is(err, ErrSilent) { t.Errorf("Expected ErrSilent for %s, got %v", tt.name, err) } else if !tt.shouldError && err != nil { t.Errorf("Expected nil error for %s, got %v", tt.name, err) @@ -52,7 +51,7 @@ func TestEchoBold(t *testing.T) { opts := options.Default().WithBold() output := testutil.CaptureOutput(func() { - _, _ = formatter.Echo(messages.Success, "Bold text", opts) + _, _ = Echo(messages.Success, "Bold text", opts) }) if !strings.Contains(output, colors.Bold) { @@ -64,7 +63,7 @@ func TestEchoItalic(t *testing.T) { opts := options.Default().WithItalic() output := testutil.CaptureOutput(func() { - _, _ = formatter.Echo(messages.Success, "Italic text", opts) + _, _ = Echo(messages.Success, "Italic text", opts) }) if !strings.Contains(output, colors.Italic) { @@ -76,7 +75,7 @@ func TestEchoNoColor(t *testing.T) { opts := options.Default().WithoutColor() output := testutil.CaptureOutput(func() { - _, _ = formatter.Echo(messages.Success, "Plain text", opts) + _, _ = Echo(messages.Success, "Plain text", opts) }) if strings.Contains(output, colors.Green) { @@ -88,7 +87,7 @@ func TestEchoNoStyle(t *testing.T) { opts := options.Default().WithBold().WithItalic().WithoutStyle() output := testutil.CaptureOutput(func() { - _, _ = formatter.Echo(messages.Success, "No style", opts) + _, _ = Echo(messages.Success, "No style", opts) }) if strings.Contains(output, colors.Bold) || strings.Contains(output, colors.Italic) { @@ -107,7 +106,7 @@ func TestEchoCallback(t *testing.T) { opts := options.Default().WithCallback(callback) - _, _ = formatter.Echo(messages.Success, "Testing callback", opts) + _, _ = Echo(messages.Success, "Testing callback", opts) if callbackType != messages.Success { t.Errorf("Expected callback type to be %v, got %v", messages.Success, callbackType) @@ -122,7 +121,7 @@ func TestEchoLogsToFile(t *testing.T) { // This test just verifies that Echo calls the logger without errors // The actual logging functionality is tested in logger_test.go output := testutil.CaptureOutput(func() { - _, _ = formatter.Echo(messages.Success, "Log test", options.Default()) + _, _ = Echo(messages.Success, "Log test", options.Default()) }) if !strings.Contains(output, "Log test") { diff --git a/tests/unit/icons_test.go b/pkg/icons/icons_test.go similarity index 55% rename from tests/unit/icons_test.go rename to pkg/icons/icons_test.go index 78b271c..7365920 100644 --- a/tests/unit/icons_test.go +++ b/pkg/icons/icons_test.go @@ -1,84 +1,83 @@ -package unit +package icons import ( "os" "testing" - "github.com/jsas4coding/utify/pkg/icons" "github.com/jsas4coding/utify/pkg/messages" ) func TestIconDetection(t *testing.T) { - detected := icons.IsNerdFontDetected() + detected := IsNerdFontDetected() _ = detected } func TestSetIconType(t *testing.T) { - original := icons.GetIconType() - defer icons.SetIconType(original) + original := GetIconType() + defer SetIconType(original) - icons.SetIconType(icons.NoIcons) - if icons.GetIconType() != icons.NoIcons { + SetIconType(NoIcons) + if GetIconType() != NoIcons { t.Error("Expected NoIcons type") } - icons.SetIconType(icons.RegularIcons) - if icons.GetIconType() != icons.RegularIcons { + SetIconType(RegularIcons) + if GetIconType() != RegularIcons { t.Error("Expected RegularIcons type") } - icons.SetIconType(icons.NerdFontIcons) - if icons.GetIconType() != icons.NerdFontIcons { + SetIconType(NerdFontIcons) + if GetIconType() != NerdFontIcons { t.Error("Expected NerdFontIcons type") } } func TestGetIcon(t *testing.T) { - original := icons.GetIconType() - defer icons.SetIconType(original) + original := GetIconType() + defer SetIconType(original) - icons.SetIconType(icons.NoIcons) - icon := icons.GetIcon(messages.Success) + SetIconType(NoIcons) + icon := GetIcon(messages.Success) if icon != "" { t.Errorf("Expected empty icon for NoIcons, got %q", icon) } - icons.SetIconType(icons.RegularIcons) - icon = icons.GetIcon(messages.Success) + SetIconType(RegularIcons) + icon = GetIcon(messages.Success) if icon == "" { t.Error("Expected non-empty icon for RegularIcons") } - icons.SetIconType(icons.NerdFontIcons) - icon = icons.GetIcon(messages.Success) + SetIconType(NerdFontIcons) + icon = GetIcon(messages.Success) if icon == "" { t.Error("Expected non-empty icon for NerdFontIcons") } } func TestIconHelperFunctions(t *testing.T) { - original := icons.GetIconType() - defer icons.SetIconType(original) + original := GetIconType() + defer SetIconType(original) - icons.ForceNerdFont() - if icons.GetIconType() != icons.NerdFontIcons { + ForceNerdFont() + if GetIconType() != NerdFontIcons { t.Error("ForceNerdFont should set NerdFontIcons") } - icons.ForceRegularIcons() - if icons.GetIconType() != icons.RegularIcons { + ForceRegularIcons() + if GetIconType() != RegularIcons { t.Error("ForceRegularIcons should set RegularIcons") } - icons.DisableIcons() - if icons.GetIconType() != icons.NoIcons { + DisableIcons() + if GetIconType() != NoIcons { t.Error("DisableIcons should set NoIcons") } } func TestAllMessageTypesHaveIcons(t *testing.T) { - original := icons.GetIconType() - defer icons.SetIconType(original) + original := GetIconType() + defer SetIconType(original) messageTypes := []messages.Type{ messages.Success, messages.Error, messages.Warning, messages.Info, @@ -90,17 +89,17 @@ func TestAllMessageTypesHaveIcons(t *testing.T) { messages.Icon, messages.Default, } - icons.SetIconType(icons.RegularIcons) + SetIconType(RegularIcons) for _, msgType := range messageTypes { - icon := icons.GetIcon(msgType) + icon := GetIcon(msgType) if icon == "" { t.Errorf("Regular icon missing for message type: %s", msgType) } } - icons.SetIconType(icons.NerdFontIcons) + SetIconType(NerdFontIcons) for _, msgType := range messageTypes { - icon := icons.GetIcon(msgType) + icon := GetIcon(msgType) if icon == "" { t.Errorf("Nerd font icon missing for message type: %s", msgType) } @@ -109,17 +108,25 @@ func TestAllMessageTypesHaveIcons(t *testing.T) { func TestNerdFontDetectionEnvVar(t *testing.T) { original := os.Getenv("NERD_FONT_ENABLED") - defer os.Setenv("NERD_FONT_ENABLED", original) + defer func() { + if err := os.Setenv("NERD_FONT_ENABLED", original); err != nil { + t.Errorf("Failed to restore original NERD_FONT_ENABLED value: %v", err) + } + }() - os.Setenv("NERD_FONT_ENABLED", "true") - icons.Init() - if icons.GetIconType() != icons.NerdFontIcons { + if err := os.Setenv("NERD_FONT_ENABLED", "true"); err != nil { + t.Errorf("Failed to set NERD_FONT_ENABLED=true: %v", err) + } + Init() + if GetIconType() != NerdFontIcons { t.Error("NERD_FONT_ENABLED=true should force Nerd Font icons") } - os.Setenv("NERD_FONT_ENABLED", "false") - icons.Init() - if icons.GetIconType() == icons.NerdFontIcons { + if err := os.Setenv("NERD_FONT_ENABLED", "false"); err != nil { + t.Errorf("Failed to set NERD_FONT_ENABLED=false: %v", err) + } + Init() + if GetIconType() == NerdFontIcons { t.Error("NERD_FONT_ENABLED=false should not force Nerd Font icons") } } diff --git a/tests/unit/logger_test.go b/pkg/logger/logger_test.go similarity index 63% rename from tests/unit/logger_test.go rename to pkg/logger/logger_test.go index 5a3bc7a..6f4032a 100644 --- a/tests/unit/logger_test.go +++ b/pkg/logger/logger_test.go @@ -1,4 +1,4 @@ -package unit +package logger import ( "encoding/json" @@ -8,7 +8,6 @@ import ( "testing" "github.com/jsas4coding/utify/internal/tests" - "github.com/jsas4coding/utify/pkg/logger" "github.com/jsas4coding/utify/pkg/messages" ) @@ -17,27 +16,27 @@ func TestSetLogTarget(t *testing.T) { tempFile := filepath.Join(tests.DataDir, "test_utify.log") defer func() { _ = os.Remove(tempFile) }() - err := logger.SetLogTarget(tempFile) + err := SetLogTarget(tempFile) if err != nil { t.Errorf("Expected no error, got %v", err) } - if logger.GetLogTarget() != tempFile { - t.Errorf("Expected log target %s, got %s", tempFile, logger.GetLogTarget()) + if GetLogTarget() != tempFile { + t.Errorf("Expected log target %s, got %s", tempFile, GetLogTarget()) } } func TestLoggingEnabled(t *testing.T) { - original := logger.IsEnabled() - defer logger.SetEnabled(original) + original := IsEnabled() + defer SetEnabled(original) - logger.SetEnabled(false) - if logger.IsEnabled() { + SetEnabled(false) + if IsEnabled() { t.Error("Expected logging to be disabled") } - logger.SetEnabled(true) - if !logger.IsEnabled() { + SetEnabled(true) + if !IsEnabled() { t.Error("Expected logging to be enabled") } } @@ -47,13 +46,13 @@ func TestLogMessage(t *testing.T) { tempFile := filepath.Join(tests.DataDir, "test_utify_message.log") defer func() { _ = os.Remove(tempFile) }() - err := logger.SetLogTarget(tempFile) + err := SetLogTarget(tempFile) if err != nil { t.Fatalf("Failed to set log target: %v", err) } - logger.LogMessage(messages.Success, "Test message") - logger.Close() + LogMessage(messages.Success, "Test message") + Close() content, err := os.ReadFile(tempFile) if err != nil { @@ -91,13 +90,13 @@ func TestLogOnly(t *testing.T) { tempFile := filepath.Join(tests.DataDir, "test_utify_only.log") defer func() { _ = os.Remove(tempFile) }() - err := logger.SetLogTarget(tempFile) + err := SetLogTarget(tempFile) if err != nil { t.Fatalf("Failed to set log target: %v", err) } - logger.LogOnly(messages.Error, "Error only message") - logger.Close() + LogOnly(messages.Error, "Error only message") + Close() content, err := os.ReadFile(tempFile) if err != nil { @@ -114,11 +113,11 @@ func TestLogFilePermissions(t *testing.T) { tempFile := filepath.Join(tests.DataDir, "test_permissions.log") defer func() { _ = os.Remove(tempFile) }() - err := logger.SetLogTarget(tempFile) + err := SetLogTarget(tempFile) if err != nil { t.Fatalf("Failed to set log target: %v", err) } - logger.Close() + Close() info, err := os.Stat(tempFile) if err != nil { @@ -133,8 +132,52 @@ func TestLogFilePermissions(t *testing.T) { func TestLogToInvalidTarget(t *testing.T) { // Attempt to log to a directory that doesn't exist and we can't create invalidTarget := "/nonexistent/dir/test.log" - err := logger.SetLogTarget(invalidTarget) + err := SetLogTarget(invalidTarget) if err == nil { t.Error("Expected an error when setting an invalid log target, but got nil") } +} + +func TestLogMessageWithDisabledLogging(t *testing.T) { + tests.CreateDataDir(t) + tempFile := filepath.Join(tests.DataDir, "test_disabled_logging.log") + defer func() { _ = os.Remove(tempFile) }() + + err := SetLogTarget(tempFile) + if err != nil { + t.Fatalf("Failed to set log target: %v", err) + } + + // Disable logging + SetEnabled(false) + defer SetEnabled(true) + + LogMessage(messages.Success, "Disabled logging message") + Close() + + content, err := os.ReadFile(tempFile) + if err != nil { + t.Fatalf("Failed to read log file: %v", err) + } + + if strings.Contains(string(content), "Disabled logging message") { + t.Error("Disabled logging should not write to log file") + } +} + +func TestGetBinaryName(t *testing.T) { + origArgs := os.Args + defer func() { os.Args = origArgs }() + + os.Args = []string{"/path/to/some/binary"} + name := getBinaryName() + if name != "binary" { + t.Errorf("Expected binary name 'binary', got %q", name) + } + + os.Args = []string{} + name = getBinaryName() + if name != "utify" { + t.Errorf("Expected fallback binary name 'utify', got %q", name) + } } \ No newline at end of file diff --git a/tests/unit/messages_test.go b/pkg/messages/messages_test.go similarity index 56% rename from tests/unit/messages_test.go rename to pkg/messages/messages_test.go index a9e9f7c..9a984ef 100644 --- a/tests/unit/messages_test.go +++ b/pkg/messages/messages_test.go @@ -1,28 +1,27 @@ -package unit +package messages import ( "testing" "github.com/jsas4coding/utify/pkg/colors" - "github.com/jsas4coding/utify/pkg/messages" ) func TestGetColor(t *testing.T) { tests := []struct { name string - msgType messages.Type + msgType Type expected string }{ - {"Success", messages.Success, colors.Green}, - {"Error", messages.Error, colors.Red}, - {"Warning", messages.Warning, colors.Yellow}, - {"Info", messages.Info, colors.Cyan}, - {"Debug", messages.Debug, colors.Gray}, + {"Success", Success, colors.Green}, + {"Error", Error, colors.Red}, + {"Warning", Warning, colors.Yellow}, + {"Info", Info, colors.Cyan}, + {"Debug", Debug, colors.Gray}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - color := messages.GetColor(tt.msgType) + color := GetColor(tt.msgType) if color != tt.expected { t.Errorf("Expected color %q for %s, got %q", tt.expected, tt.msgType, color) } @@ -33,20 +32,20 @@ func TestGetColor(t *testing.T) { func TestIsErrorType(t *testing.T) { tests := []struct { name string - msgType messages.Type + msgType Type isError bool }{ - {"Error", messages.Error, true}, - {"Critical", messages.Critical, true}, - {"Debug", messages.Debug, true}, - {"Success", messages.Success, false}, - {"Warning", messages.Warning, false}, - {"Info", messages.Info, false}, + {"Error", Error, true}, + {"Critical", Critical, true}, + {"Debug", Debug, true}, + {"Success", Success, false}, + {"Warning", Warning, false}, + {"Info", Info, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result := messages.IsErrorType(tt.msgType) + result := IsErrorType(tt.msgType) if result != tt.isError { t.Errorf("Expected IsErrorType(%s) to be %v, got %v", tt.msgType, tt.isError, result) } @@ -58,10 +57,10 @@ func TestGetColorWithUserOverride(t *testing.T) { colors.ClearUserColors() customColor := "\033[95m" colors.SetColorTable(map[string]string{ - string(messages.Success): customColor, + string(Success): customColor, }) - color := messages.GetColor(messages.Success) + color := GetColor(Success) if color != customColor { t.Errorf("Expected custom color %q for success, got %q", customColor, color) } diff --git a/tests/unit/options_test.go b/pkg/options/options_test.go similarity index 70% rename from tests/unit/options_test.go rename to pkg/options/options_test.go index 76a8cc5..8ea497c 100644 --- a/tests/unit/options_test.go +++ b/pkg/options/options_test.go @@ -1,14 +1,13 @@ -package unit +package options import ( "testing" "github.com/jsas4coding/utify/pkg/messages" - "github.com/jsas4coding/utify/pkg/options" ) func TestOptionsDefault(t *testing.T) { - opts := options.Default() + opts := Default() if opts.Bold || opts.Italic || opts.NoColor || opts.NoIcon || opts.NoStyle || opts.Exit { t.Error("Default options should have all flags set to false") @@ -20,7 +19,7 @@ func TestOptionsDefault(t *testing.T) { } func TestWithBold(t *testing.T) { - opts := options.Default().WithBold() + opts := Default().WithBold() if !opts.Bold { t.Error("WithBold should set Bold to true") @@ -28,7 +27,7 @@ func TestWithBold(t *testing.T) { } func TestWithItalic(t *testing.T) { - opts := options.Default().WithItalic() + opts := Default().WithItalic() if !opts.Italic { t.Error("WithItalic should set Italic to true") @@ -36,7 +35,7 @@ func TestWithItalic(t *testing.T) { } func TestWithoutColor(t *testing.T) { - opts := options.Default().WithoutColor() + opts := Default().WithoutColor() if !opts.NoColor { t.Error("WithoutColor should set NoColor to true") @@ -44,7 +43,7 @@ func TestWithoutColor(t *testing.T) { } func TestWithoutStyle(t *testing.T) { - opts := options.Default().WithoutStyle() + opts := Default().WithoutStyle() if !opts.NoStyle { t.Error("WithoutStyle should set NoStyle to true") @@ -52,7 +51,7 @@ func TestWithoutStyle(t *testing.T) { } func TestWithExit(t *testing.T) { - opts := options.Default().WithExit() + opts := Default().WithExit() if !opts.Exit { t.Error("WithExit should set Exit to true") @@ -69,7 +68,7 @@ func TestWithCallback(t *testing.T) { called = true } - opts := options.Default().WithCallback(callback) + opts := Default().WithCallback(callback) if opts.Callback == nil { t.Error("WithCallback should set callback function") @@ -89,7 +88,7 @@ func TestWithCallback(t *testing.T) { func TestExitDisablesCallback(t *testing.T) { callback := func(_ messages.Type, _ string) {} - opts := options.Default().WithCallback(callback).WithExit() + opts := Default().WithCallback(callback).WithExit() if opts.Callback != nil { t.Error("WithExit should disable callback") @@ -103,7 +102,7 @@ func TestExitDisablesCallback(t *testing.T) { func TestCallbackDisablesExit(t *testing.T) { callback := func(_ messages.Type, _ string) {} - opts := options.Default().WithExit().WithCallback(callback) + opts := Default().WithExit().WithCallback(callback) if opts.Exit { t.Error("WithCallback should disable exit") @@ -113,3 +112,27 @@ func TestCallbackDisablesExit(t *testing.T) { t.Error("WithCallback should enable callback") } } + +func TestWithIcon(t *testing.T) { + opts := Default().WithIcon() + + if !opts.ShowIcons { + t.Error("WithIcon should set ShowIcons to true") + } + + if opts.NoIcon { + t.Error("WithIcon should set NoIcon to false") + } +} + +func TestWithoutIcon(t *testing.T) { + opts := Default().WithoutIcon() + + if opts.ShowIcons { + t.Error("WithoutIcon should set ShowIcons to false") + } + + if !opts.NoIcon { + t.Error("WithoutIcon should set NoIcon to true") + } +} diff --git a/tests/unit/utify_test.go b/tests/unit/utify_test.go deleted file mode 100644 index 238999c..0000000 --- a/tests/unit/utify_test.go +++ /dev/null @@ -1,237 +0,0 @@ -package unit - -import ( - "os" - "path/filepath" - "testing" - - "github.com/jsas4coding/utify" -) - -func defaultOpts() *utify.Options { - return utify.OptionsDefault() -} - -func TestBasicOutputFunctions(t *testing.T) { - tests := []struct { - name string - fn func(string, *utify.Options) - }{ - {"Success", utify.Success}, - {"Error", utify.Error}, - {"Warning", utify.Warning}, - {"Info", utify.Info}, - {"Debug", utify.Debug}, - {"Critical", utify.Critical}, - {"Delete", utify.Delete}, - {"Update", utify.Update}, - {"Install", utify.Install}, - {"Upgrade", utify.Upgrade}, - {"Edit", utify.Edit}, - {"New", utify.New}, - {"Download", utify.Download}, - {"Upload", utify.Upload}, - {"Sync", utify.Sync}, - {"Search", utify.Search}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt := tt - tt.fn("Test message", defaultOpts()) - }) - } -} - -func TestFormattedOutputFunctions(t *testing.T) { - tests := []struct { - name string - fn func(string, *utify.Options, ...any) - }{ - {"Successf", utify.Successf}, - {"Errorf", utify.Errorf}, - {"Warningf", utify.Warningf}, - {"Infof", utify.Infof}, - {"Debugf", utify.Debugf}, - {"Criticalf", utify.Criticalf}, - {"Deletef", utify.Deletef}, - {"Updatef", utify.Updatef}, - {"Installf", utify.Installf}, - {"Upgradef", utify.Upgradef}, - {"Editf", utify.Editf}, - {"Newf", utify.Newf}, - {"Downloadf", utify.Downloadf}, - {"Uploadf", utify.Uploadf}, - {"Syncf", utify.Syncf}, - {"Searchf", utify.Searchf}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt := tt - tt.fn("Formatted %s", defaultOpts(), "message") - }) - } -} - -func TestGetFunctions(t *testing.T) { - tests := []struct { - name string - fn func(string, *utify.Options) (string, error) - }{ - {"GetSuccess", utify.GetSuccess}, - {"GetError", utify.GetError}, - {"GetWarning", utify.GetWarning}, - {"GetInfo", utify.GetInfo}, - {"GetDebug", utify.GetDebug}, - {"GetCritical", utify.GetCritical}, - {"GetDelete", utify.GetDelete}, - {"GetUpdate", utify.GetUpdate}, - {"GetInstall", utify.GetInstall}, - {"GetUpgrade", utify.GetUpgrade}, - {"GetEdit", utify.GetEdit}, - {"GetNew", utify.GetNew}, - {"GetDownload", utify.GetDownload}, - {"GetUpload", utify.GetUpload}, - {"GetSync", utify.GetSync}, - {"GetSearch", utify.GetSearch}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - _, err := tt.fn("Test message", defaultOpts()) - if err != nil && err != utify.ErrSilent { - t.Errorf("%s returned unexpected error: %v", tt.name, err) - } - }) - } -} - -func TestLogOnlyFunctions(t *testing.T) { - tests := []struct { - name string - fn func(string) - }{ - {"LogSuccess", utify.LogSuccess}, - {"LogError", utify.LogError}, - {"LogWarning", utify.LogWarning}, - {"LogInfo", utify.LogInfo}, - {"LogDebug", utify.LogDebug}, - {"LogCritical", utify.LogCritical}, - {"LogDelete", utify.LogDelete}, - {"LogUpdate", utify.LogUpdate}, - {"LogInstall", utify.LogInstall}, - {"LogUpgrade", utify.LogUpgrade}, - {"LogEdit", utify.LogEdit}, - {"LogNew", utify.LogNew}, - {"LogDownload", utify.LogDownload}, - {"LogUpload", utify.LogUpload}, - {"LogSync", utify.LogSync}, - {"LogSearch", utify.LogSearch}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt := tt - tt.fn("Log-only message") - }) - } -} - -func TestConfigFunctions(t *testing.T) { - t.Run("SetColorTable", func(t *testing.T) { - utify.SetColorTable(map[string]string{ - "Red": "#FF0000", - "Blue": "#0000FF", - }) - }) - - t.Run("SetLogTargetAndGet", func(t *testing.T) { - tmpfile := filepath.Join(os.TempDir(), "utify_test.log") - err := utify.SetLogTarget(tmpfile) - if err != nil { - t.Fatalf("SetLogTarget failed: %v", err) - } - got := utify.GetLogTarget() - if got != tmpfile { - t.Errorf("expected log target %s, got %s", tmpfile, got) - } - utify.CloseLogger() - }) - - t.Run("SetLoggingEnabled", func(t *testing.T) { - utify.SetLoggingEnabled(true) - if !utify.IsLoggingEnabled() { - t.Error("expected logging to be enabled") - } - utify.SetLoggingEnabled(false) - if utify.IsLoggingEnabled() { - t.Error("expected logging to be disabled") - } - }) - - t.Run("ForceIconsModes", func(t *testing.T) { - utify.ForceNerdFont() - utify.ForceRegularIcons() - utify.DisableIcons() - _ = utify.IsNerdFontDetected() - _ = utify.GetIconType() - }) -} - -func TestGetFormattedFunctions(t *testing.T) { - tests := []struct { - name string - fn func(string, *utify.Options, ...any) (string, error) - }{ - {"GetSuccessf", utify.GetSuccessf}, - {"GetErrorf", utify.GetErrorf}, - {"GetWarningf", utify.GetWarningf}, - {"GetInfof", utify.GetInfof}, - {"GetDebugf", utify.GetDebugf}, - {"GetCriticalf", utify.GetCriticalf}, - {"GetDeletef", utify.GetDeletef}, - {"GetUpdatef", utify.GetUpdatef}, - {"GetInstallf", utify.GetInstallf}, - {"GetUpgradef", utify.GetUpgradef}, - {"GetEditf", utify.GetEditf}, - {"GetNewf", utify.GetNewf}, - {"GetDownloadf", utify.GetDownloadf}, - {"GetUploadf", utify.GetUploadf}, - {"GetSyncf", utify.GetSyncf}, - {"GetSearchf", utify.GetSearchf}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - _, err := tt.fn("Formatted %s", defaultOpts(), "message") - if err != nil && err != utify.ErrSilent { - t.Errorf("%s returned unexpected error: %v", tt.name, err) - } - }) - } -} - -func TestLogFormattedFunctions(t *testing.T) { - tests := []struct { - name string - fn func(string, ...any) - }{ - {"LogSuccessf", utify.LogSuccessf}, - {"LogErrorf", utify.LogErrorf}, - {"LogWarningf", utify.LogWarningf}, - {"LogInfof", utify.LogInfof}, - {"LogDebugf", utify.LogDebugf}, - {"LogCriticalf", utify.LogCriticalf}, - {"LogDeletef", utify.LogDeletef}, - {"LogUpdatef", utify.LogUpdatef}, - {"LogInstallf", utify.LogInstallf}, - {"LogUpgradef", utify.LogUpgradef}, - {"LogEditf", utify.LogEditf}, - {"LogNewf", utify.LogNewf}, - {"LogDownloadf", utify.LogDownloadf}, - {"LogUploadf", utify.LogUploadf}, - {"LogSyncf", utify.LogSyncf}, - {"LogSearchf", utify.LogSearchf}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.fn("Formatted %s", "message") - }) - } -} diff --git a/utify_test.go b/utify_test.go new file mode 100644 index 0000000..076e702 --- /dev/null +++ b/utify_test.go @@ -0,0 +1,235 @@ +package utify + +import ( + "os" + "path/filepath" + "testing" +) + +func defaultOpts() *Options { + return OptionsDefault() +} + +func TestBasicOutputFunctions(t *testing.T) { + tests := []struct { + name string + fn func(string, *Options) + }{ + {"Success", Success}, + {"Error", Error}, + {"Warning", Warning}, + {"Info", Info}, + {"Debug", Debug}, + {"Critical", Critical}, + {"Delete", Delete}, + {"Update", Update}, + {"Install", Install}, + {"Upgrade", Upgrade}, + {"Edit", Edit}, + {"New", New}, + {"Download", Download}, + {"Upload", Upload}, + {"Sync", Sync}, + {"Search", Search}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt := tt + tt.fn("Test message", defaultOpts()) + }) + } +} + +func TestFormattedOutputFunctions(t *testing.T) { + tests := []struct { + name string + fn func(string, *Options, ...any) + }{ + {"Successf", Successf}, + {"Errorf", Errorf}, + {"Warningf", Warningf}, + {"Infof", Infof}, + {"Debugf", Debugf}, + {"Criticalf", Criticalf}, + {"Deletef", Deletef}, + {"Updatef", Updatef}, + {"Installf", Installf}, + {"Upgradef", Upgradef}, + {"Editf", Editf}, + {"Newf", Newf}, + {"Downloadf", Downloadf}, + {"Uploadf", Uploadf}, + {"Syncf", Syncf}, + {"Searchf", Searchf}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt := tt + tt.fn("Formatted %s", defaultOpts(), "message") + }) + } +} + +func TestGetFunctions(t *testing.T) { + tests := []struct { + name string + fn func(string, *Options) (string, error) + }{ + {"GetSuccess", GetSuccess}, + {"GetError", GetError}, + {"GetWarning", GetWarning}, + {"GetInfo", GetInfo}, + {"GetDebug", GetDebug}, + {"GetCritical", GetCritical}, + {"GetDelete", GetDelete}, + {"GetUpdate", GetUpdate}, + {"GetInstall", GetInstall}, + {"GetUpgrade", GetUpgrade}, + {"GetEdit", GetEdit}, + {"GetNew", GetNew}, + {"GetDownload", GetDownload}, + {"GetUpload", GetUpload}, + {"GetSync", GetSync}, + {"GetSearch", GetSearch}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := tt.fn("Test message", defaultOpts()) + if err != nil && err != ErrSilent { + t.Errorf("%s returned unexpected error: %v", tt.name, err) + } + }) + } +} + +func TestLogOnlyFunctions(t *testing.T) { + tests := []struct { + name string + fn func(string) + }{ + {"LogSuccess", LogSuccess}, + {"LogError", LogError}, + {"LogWarning", LogWarning}, + {"LogInfo", LogInfo}, + {"LogDebug", LogDebug}, + {"LogCritical", LogCritical}, + {"LogDelete", LogDelete}, + {"LogUpdate", LogUpdate}, + {"LogInstall", LogInstall}, + {"LogUpgrade", LogUpgrade}, + {"LogEdit", LogEdit}, + {"LogNew", LogNew}, + {"LogDownload", LogDownload}, + {"LogUpload", LogUpload}, + {"LogSync", LogSync}, + {"LogSearch", LogSearch}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt := tt + tt.fn("Log-only message") + }) + } +} + +func TestConfigFunctions(t *testing.T) { + t.Run("SetColorTable", func(t *testing.T) { + SetColorTable(map[string]string{ + "Red": "#FF0000", + "Blue": "#0000FF", + }) + }) + + t.Run("SetLogTargetAndGet", func(t *testing.T) { + tmpfile := filepath.Join(os.TempDir(), "utify_test.log") + err := SetLogTarget(tmpfile) + if err != nil { + t.Fatalf("SetLogTarget failed: %v", err) + } + got := GetLogTarget() + if got != tmpfile { + t.Errorf("expected log target %s, got %s", tmpfile, got) + } + CloseLogger() + }) + + t.Run("SetLoggingEnabled", func(t *testing.T) { + SetLoggingEnabled(true) + if !IsLoggingEnabled() { + t.Error("expected logging to be enabled") + } + SetLoggingEnabled(false) + if IsLoggingEnabled() { + t.Error("expected logging to be disabled") + } + }) + + t.Run("ForceIconsModes", func(t *testing.T) { + ForceNerdFont() + ForceRegularIcons() + DisableIcons() + _ = IsNerdFontDetected() + _ = GetIconType() + }) +} + +func TestGetFormattedFunctions(t *testing.T) { + tests := []struct { + name string + fn func(string, *Options, ...any) (string, error) + }{ + {"GetSuccessf", GetSuccessf}, + {"GetErrorf", GetErrorf}, + {"GetWarningf", GetWarningf}, + {"GetInfof", GetInfof}, + {"GetDebugf", GetDebugf}, + {"GetCriticalf", GetCriticalf}, + {"GetDeletef", GetDeletef}, + {"GetUpdatef", GetUpdatef}, + {"GetInstallf", GetInstallf}, + {"GetUpgradef", GetUpgradef}, + {"GetEditf", GetEditf}, + {"GetNewf", GetNewf}, + {"GetDownloadf", GetDownloadf}, + {"GetUploadf", GetUploadf}, + {"GetSyncf", GetSyncf}, + {"GetSearchf", GetSearchf}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := tt.fn("Formatted %s", defaultOpts(), "message") + if err != nil && err != ErrSilent { + t.Errorf("%s returned unexpected error: %v", tt.name, err) + } + }) + } +} + +func TestLogFormattedFunctions(t *testing.T) { + tests := []struct { + name string + fn func(string, ...any) + }{ + {"LogSuccessf", LogSuccessf}, + {"LogErrorf", LogErrorf}, + {"LogWarningf", LogWarningf}, + {"LogInfof", LogInfof}, + {"LogDebugf", LogDebugf}, + {"LogCriticalf", LogCriticalf}, + {"LogDeletef", LogDeletef}, + {"LogUpdatef", LogUpdatef}, + {"LogInstallf", LogInstallf}, + {"LogUpgradef", LogUpgradef}, + {"LogEditf", LogEditf}, + {"LogNewf", LogNewf}, + {"LogDownloadf", LogDownloadf}, + {"LogUploadf", LogUploadf}, + {"LogSyncf", LogSyncf}, + {"LogSearchf", LogSearchf}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.fn("Formatted %s", "message") + }) + } +} From fd80ccee9f155f404bd8bda73bf2e68409af99c3 Mon Sep 17 00:00:00 2001 From: Jonatas Sas Date: Thu, 31 Jul 2025 12:43:50 -0300 Subject: [PATCH 8/8] Coverage and Tests Updates --- .github/workflows/utify.yml | 6 ++---- Makefile | 4 ++-- changelogs/1.4.13.md | 10 ++++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/utify.yml b/.github/workflows/utify.yml index 7116e4a..838ca4a 100644 --- a/.github/workflows/utify.yml +++ b/.github/workflows/utify.yml @@ -41,12 +41,10 @@ jobs: fi - name: Run tests with full coverage (all packages + tests) run: | - PKGS=$(go list ./pkg/... ./internal/... | grep -vE '/examples') - echo "Packages for coverage:" $PKGS - go test -v -race -timeout=10m -coverpkg=$(echo $PKGS | paste -sd, -) -coverprofile=coverage.out ./pkg/... ./internal/... ./tests/... + go test -v -race -timeout=10m -covermode=atomic -coverprofile=coverage.out $(go list ./... | grep -v /examples) - name: Run benchmarks run: go test -bench=. -benchtime=5s ./tests/benchmarks/... - - name: Fail if coverage is below 90% + - name: Analyze coverage run: | go tool cover -func=coverage.out COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//') diff --git a/Makefile b/Makefile index f672b3c..e10351c 100644 --- a/Makefile +++ b/Makefile @@ -52,13 +52,13 @@ bench: # Run tests with coverage and generate report coverage: @echo "๐Ÿ“Š Running tests with coverage..." - @go test -coverprofile=coverage.out ./tests/... ./pkg/... ./internal/... -cover -coverpkg=./pkg/...,./internal/... + @go test -covermode=atomic -coverprofile=coverage.out $$(go list ./... | grep -v /examples) @go tool cover -func=coverage.out # Generate HTML coverage report coverage-html: @echo "๐Ÿ“Š Generating HTML coverage report..." - @go test -coverprofile=coverage.out ./tests/... ./pkg/... ./internal/... -cover -coverpkg=./pkg/...,./internal/... + @go test -covermode=atomic -coverprofile=coverage.out $$(go list ./... | grep -v /examples) @go tool cover -html=coverage.out -o coverage.html @echo "โœ… Coverage report generated: coverage.html" diff --git a/changelogs/1.4.13.md b/changelogs/1.4.13.md index 16c1f4d..9ce2aa3 100644 --- a/changelogs/1.4.13.md +++ b/changelogs/1.4.13.md @@ -20,10 +20,12 @@ - **Test Structure Improvements:** - Restructured unit tests to be located in their corresponding package directories. - Moved tests from `tests/unit/` to respective package directories (e.g., `pkg/colors/colors_test.go`). - - Improved test coverage across multiple packages: - - `pkg/options`: Achieved 100% test coverage - - `pkg/logger`: Increased test coverage to 82.5% - - Added more comprehensive test cases for edge cases and different code paths. + - Updated test coverage configuration to use atomic mode and exclude example files. + - Introduced more robust coverage tracking mechanism + - Current focus areas for test improvement: + - Enhance edge case testing in logging and icon detection + - Expand integration test scenarios + - Add performance and concurrency tests ### ๐Ÿ”ง Project Structure