• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

abdulkader138 / personal-expense-tracker / #85

13 Jan 2026 08:47PM UTC coverage: 99.473% (+0.7%) from 98.739%
#85

push

abdulkader138
code refactoring

37 of 40 new or added lines in 3 files covered. (92.5%)

1 existing line in 1 file now uncovered.

1321 of 1328 relevant lines covered (99.47%)

0.99 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.44
/src/main/java/com/mycompany/pet/controller/CategoryController.java
1
package com.mycompany.pet.controller;
2

3
import java.sql.SQLException;
4
import java.util.List;
5
import java.util.function.Consumer;
6

7
import com.mycompany.pet.model.Category;
8
import com.mycompany.pet.service.CategoryService;
9

10
/**
11
 * Controller for Category operations.
12
 * Separates UI concerns from business logic.
13
 * 
14
 * This controller handles:
15
 * - Category CRUD operations
16
 * - Error handling and user feedback
17
 * - Thread-safe database operations
18
 */
19
public class CategoryController {
20
    private final CategoryService categoryService;
21
    
22
    public CategoryController(CategoryService categoryService) {
1✔
23
        this.categoryService = categoryService;
1✔
24
    }
1✔
25
    
26
    /**
27
     * Load all categories.
28
     * 
29
     * @param onSuccess Callback with list of categories
30
     * @param onError Callback with error message
31
     */
32
    public void loadCategories(Consumer<List<Category>> onSuccess, Consumer<String> onError) {
33
        executeAsync(() -> {
1✔
34
            try {
35
                List<Category> categories = categoryService.getAllCategories();
1✔
36
                invokeOnSwingThread(() -> onSuccess.accept(categories));
1✔
NEW
37
            } catch (IllegalArgumentException e) {
×
NEW
38
                invokeOnSwingThread(() -> onError.accept(e.getMessage()));
×
39
            } catch (SQLException | RuntimeException e) {
1✔
40
                handleError("Error loading categories", e.getMessage(), onError);
1✔
41
            }
1✔
42
        });
1✔
43
    }
1✔
44
    
45
    /**
46
     * Create a new category.
47
     * 
48
     * @param name Category name
49
     * @param onSuccess Callback with created category
50
     * @param onError Callback with error message
51
     */
52
    public void createCategory(String name, Consumer<Category> onSuccess, Consumer<String> onError) {
53
        if (!validateCategoryName(name, onError)) {
1✔
54
            return;
1✔
55
        }
56
        
57
        executeAsync(() -> {
1✔
58
            try {
59
                Category category = categoryService.createCategory(name.trim());
1✔
60
                invokeOnSwingThread(() -> onSuccess.accept(category));
1✔
UNCOV
61
            } catch (IllegalArgumentException e) {
×
NEW
62
                invokeOnSwingThread(() -> onError.accept(e.getMessage()));
×
63
            } catch (SQLException | RuntimeException e) {
1✔
64
                handleError("Error adding category", e.getMessage(), onError);
1✔
65
            }
1✔
66
        });
1✔
67
    }
1✔
68
    
69
    /**
70
     * Update an existing category.
71
     * 
72
     * @param categoryId Category ID
73
     * @param name New category name
74
     * @param onSuccess Callback with updated category
75
     * @param onError Callback with error message
76
     */
77
    public void updateCategory(Integer categoryId, String name, 
78
                               Consumer<Category> onSuccess, Consumer<String> onError) {
79
        if (!validateCategoryName(name, onError)) {
1✔
80
            return;
1✔
81
        }
82
        
83
        executeAsync(() -> {
1✔
84
            try {
85
                Category category = categoryService.updateCategory(categoryId, name.trim());
1✔
86
                invokeOnSwingThread(() -> onSuccess.accept(category));
1✔
87
            } catch (IllegalArgumentException e) {
1✔
88
                invokeOnSwingThread(() -> onError.accept(e.getMessage()));
1✔
89
            } catch (SQLException | RuntimeException e) {
1✔
90
                handleError("Error updating category", e.getMessage(), onError);
1✔
91
            }
1✔
92
        });
1✔
93
    }
1✔
94
    
95
    /**
96
     * Delete a category.
97
     * 
98
     * @param categoryId Category ID
99
     * @param onSuccess Callback when deletion succeeds
100
     * @param onError Callback with error message
101
     */
102
    public void deleteCategory(Integer categoryId, Runnable onSuccess, Consumer<String> onError) {
103
        executeAsync(() -> {
1✔
104
            try {
105
                categoryService.deleteCategory(categoryId);
1✔
106
                invokeOnSwingThread(onSuccess);
1✔
107
            } catch (IllegalArgumentException e) {
1✔
108
                invokeOnSwingThread(() -> onError.accept(e.getMessage()));
1✔
109
            } catch (SQLException | RuntimeException e) {
1✔
110
                handleError("Error deleting category", e.getMessage(), onError);
1✔
111
            }
1✔
112
        });
1✔
113
    }
1✔
114
    
115
    /**
116
     * Get a category by ID.
117
     * 
118
     * @param categoryId Category ID
119
     * @return Category or null if not found
120
     * @throws SQLException if database error occurs
121
     */
122
    public Category getCategory(Integer categoryId) throws SQLException {
123
        return categoryService.getCategory(categoryId);
1✔
124
    }
125
    
126
    /**
127
     * Validates category name and invokes error callback if invalid.
128
     * 
129
     * @param name Category name to validate
130
     * @param onError Error callback
131
     * @return true if valid, false otherwise
132
     */
133
    private boolean validateCategoryName(String name, Consumer<String> onError) {
134
        if (name == null || name.trim().isEmpty()) {
1✔
135
            invokeOnSwingThread(() -> onError.accept("Category name cannot be empty."));
1✔
136
            return false;
1✔
137
        }
138
        return true;
1✔
139
    }
140
    
141
    /**
142
     * Executes an operation asynchronously in a daemon thread.
143
     * 
144
     * @param operation The operation to execute
145
     */
146
    private void executeAsync(Runnable operation) {
147
        Thread thread = new Thread(operation);
1✔
148
        thread.setDaemon(true);
1✔
149
        thread.start();
1✔
150
    }
1✔
151
    
152
    /**
153
     * Handles errors by formatting message and invoking error callback on Swing thread.
154
     * 
155
     * @param errorPrefix Prefix for error message
156
     * @param errorMessage Error message
157
     * @param onError Error callback
158
     */
159
    private void handleError(String errorPrefix, String errorMessage, Consumer<String> onError) {
160
        String errorMsg = errorPrefix + ": " + errorMessage;
1✔
161
        invokeOnSwingThread(() -> onError.accept(errorMsg));
1✔
162
    }
1✔
163
    
164
    /**
165
     * Invokes a runnable on the Swing event dispatch thread.
166
     * 
167
     * @param runnable The runnable to execute
168
     */
169
    private void invokeOnSwingThread(Runnable runnable) {
170
        javax.swing.SwingUtilities.invokeLater(runnable);
1✔
171
    }
1✔
172
}
173

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc