refactor: comprehensive code quality improvements

- Add logger to all exporters for consistent error handling
- Add Course.Validate() method with ValidationError type
- Create shared test fixtures in internal/testdata
- Refactor config passing: NewArticulateParser now takes *config.Config
- Add NewLoggerFromConfig() factory for logger creation
- Add context cancellation with signal handling (SIGINT/SIGTERM)
- Add godoc examples for loggers and exporters
- Add HTML exporter error path tests
- Add fuzz tests for parser and HTMLCleaner
- Fix markdown output: trim whitespace, collapse blank lines
- Remove test output files from repo
This commit is contained in:
2026-09-21 09:45:05 +02:00
parent 8ec9dd4f20
commit adb60ca7e5
29 changed files with 1940 additions and 415 deletions
+11 -11
View File
@@ -7,11 +7,12 @@ import (
"context"
"fmt"
"os"
"os/signal"
"strings"
"syscall"
"github.com/kjanat/articulate-parser/internal/config"
"github.com/kjanat/articulate-parser/internal/exporters"
"github.com/kjanat/articulate-parser/internal/interfaces"
"github.com/kjanat/articulate-parser/internal/services"
"github.com/kjanat/articulate-parser/internal/version"
)
@@ -26,20 +27,19 @@ func main() {
// run contains the main application logic and returns an exit code.
// This function is testable as it doesn't call os.Exit directly.
func run(args []string) int {
// Create context that cancels on interrupt signals (SIGINT, SIGTERM)
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer cancel()
// Load configuration
cfg := config.Load()
// Dependency injection setup with configuration
var logger interfaces.Logger
if cfg.LogFormat == "json" {
logger = services.NewSlogLogger(cfg.LogLevel)
} else {
logger = services.NewTextLogger(cfg.LogLevel)
}
logger := services.NewLoggerFromConfig(cfg)
htmlCleaner := services.NewHTMLCleaner()
parser := services.NewArticulateParser(logger, cfg.BaseURL, cfg.RequestTimeout)
exporterFactory := exporters.NewFactory(htmlCleaner)
parser := services.NewArticulateParser(logger, cfg)
exporterFactory := exporters.NewFactory(htmlCleaner, logger)
app := services.NewApp(parser, exporterFactory)
// Check for version flag
@@ -70,9 +70,9 @@ func run(args []string) int {
// Determine if source is a URI or file path
if isURI(source) {
err = app.ProcessCourseFromURI(context.Background(), source, format, output)
err = app.ProcessCourseFromURI(ctx, source, format, output)
} else {
err = app.ProcessCourseFromFile(source, format, output)
err = app.ProcessCourseFromFile(ctx, source, format, output)
}
if err != nil {