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

hazendaz / smartsprites / 555

21 May 2026 03:26PM UTC coverage: 87.799%. Remained the same
555

push

github

hazendaz
[tests] Fix tests that were looking at size of original license before spdx change

557 of 670 branches covered (83.13%)

Branch coverage included in aggregate %.

1350 of 1502 relevant lines covered (89.88%)

0.9 hits per line

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

96.55
/src/main/java/org/carrot2/labs/smartsprites/SmartSpritesParameters.java
1
/*
2
 * SPDX-License-Identifier: BSD-3-Clause
3
 * See LICENSE file for details.
4
 *
5
 * Copyright 2021-2026 Hazendaz
6
 * Copyright (C) 2007-2009, Stanisław Osiński.
7
 */
8
package org.carrot2.labs.smartsprites;
9

10
import java.io.File;
11
import java.io.IOException;
12
import java.nio.charset.StandardCharsets;
13
import java.nio.file.Path;
14
import java.util.List;
15

16
import org.carrot2.labs.smartsprites.message.Message.MessageLevel;
17
import org.carrot2.labs.smartsprites.message.Message.MessageType;
18
import org.carrot2.labs.smartsprites.message.MessageLog;
19
import org.carrot2.util.FileUtils;
20
import org.carrot2.util.StringUtils;
21
import org.kohsuke.args4j.Argument;
22
import org.kohsuke.args4j.Option;
23

24
/**
25
 * Contains invocation parameters for SmartSprites, provides methods for validating the parameters.
26
 */
27
public final class SmartSpritesParameters {
28
    /**
29
     * Path to the directory that contains the css files to be processed. Directories containing CSS and image files
30
     * must be writable, unless output.dir.path is provided. The root.dir.path can be either absolute, e.g.
31
     * c:/myproject/web or relative to the directory in which this script is run.
32
     */
33
    @Option(name = "--root-dir-path", required = false, metaVar = "DIR")
34
    private String rootDir;
35

36
    /**
37
     * Paths to individual CSS files to process. Either {@link #rootDir} or {@link #cssFiles} must be not empty. If only
38
     * {@link #cssFiles} is not empty, {@link #outputDir} must be blank. If both {@link #rootDir} and {@link #cssFiles}
39
     * are not empty, {@link #outputDir} is supported but only {@link #cssFiles} from {@link #rootDir} are processed.
40
     */
41
    @Argument(metaVar = "CSS-FILES")
42
    @Option(name = "--css-files", required = false, metaVar = "FILES")
43
    private List<String> cssFiles;
44

45
    /**
46
     * Output directory for processed CSS files and CSS-relative sprite images. The directory structure relative to
47
     * root.dir.path will be preserved in the output directory. E.g. if CSS files are contained in the css/base
48
     * directory of root.dir.path, the processed results will be written to output.dir.path/css/base. Also, CSS-relative
49
     * sprite images will be written to the output directory. Sprite images with document-root-relative URLs will be
50
     * written relative to the document.root.dir.path.
51
     * <p>
52
     * If the output.dir.path directory does not exist, it will be created.
53
     * <p>
54
     * You can leave this property empty, in which case the CSS files will be written next to the original CSS files
55
     * with css.file.suffix, and sprite images will be written relative to CSS files.
56
     * <p>
57
     * If you are using a non-empty output.dir.path, you might want to use an empty css.file.suffix.
58
     */
59
    @Option(name = "--output-dir-path", metaVar = "DIR")
60
    private String outputDir;
61

62
    /**
63
     * Document root path for document-root-relative (starting with '/') image urls in CSS. All such image URLs will be
64
     * taken relative to document.root.dir.path. Also document-root-relative sprite URLs will be written relative to
65
     * document.root.dir.path. You can leave this property empty if your CSS uses only CSS-relative image URLs. *
66
     */
67
    @Option(name = "--document-root-dir-path", metaVar = "DIR")
68
    private String documentRootDir;
69

70
    /**
71
     * Message logging level. If you're getting lots of INFO messages and want to see only warnings, set this option to
72
     * WARN.
73
     */
74
    @Option(name = "--log-level")
75
    private MessageLevel logLevel;
76

77
    /**
78
     * The encoding to assume for input and output CSS files.
79
     */
80
    @Option(name = "--css-file-encoding")
81
    private String cssFileEncoding;
82

83
    /**
84
     * Suffix to be appended to the processed CSS file name.
85
     */
86
    @Option(name = "--css-file-suffix")
87
    private String cssFileSuffix;
88

89
    /**
90
     * The required depth of the generated PNG sprites.
91
     */
92
    @Option(name = "--sprite-png-depth")
93
    private PngDepth spritePngDepth;
94

95
    /**
96
     * If <code>true</code>, SmartSprites will generate the sprite directive indicating that the image is a sprite
97
     * image.
98
     */
99
    @Option(name = "--mark-sprite-images")
100
    private boolean markSpriteImages;
101

102
    /** The default suffix to be added to the generated CSS files. */
103
    public static final String DEFAULT_CSS_FILE_SUFFIX = "-sprite";
104

105
    /** By default, we use full color only when necessary. */
106
    public static final PngDepth DEFAULT_SPRITE_PNG_DEPTH = PngDepth.AUTO;
1✔
107

108
    /** By default, we'll assume CSS files are UTF-8 encoded. */
109
    public static final String DEFAULT_CSS_FILE_ENCODING = StandardCharsets.UTF_8.name();
1✔
110

111
    /** The default logging level. */
112
    public static final MessageLevel DEFAULT_LOGGING_LEVEL = MessageLevel.INFO;
1✔
113

114
    /** By default, we don't generate sprite directive in output css. */
115
    public static final boolean DEFAULT_MARK_SPRITE_IMAGES = false;
116

117
    /**
118
     * The Enum PngDepth.
119
     */
120
    public enum PngDepth {
1✔
121

122
        /** The auto. */
123
        AUTO,
1✔
124
        /** The indexed. */
125
        INDEXED,
1✔
126
        /** The direct. */
127
        DIRECT;
1✔
128
    }
129

130
    /**
131
     * Creates the parameters with default options and null root dir, before root dir is set, the parameters are
132
     * invalid.
133
     */
134
    public SmartSpritesParameters() {
135
        this(null);
1✔
136
    }
1✔
137

138
    /**
139
     * Creates the parameters with most default values.
140
     *
141
     * @param rootDir
142
     *            the root dir
143
     */
144
    public SmartSpritesParameters(String rootDir) {
145
        this(rootDir, null, null, null, MessageLevel.INFO, DEFAULT_CSS_FILE_SUFFIX, DEFAULT_SPRITE_PNG_DEPTH,
1✔
146
                DEFAULT_CSS_FILE_ENCODING, DEFAULT_MARK_SPRITE_IMAGES);
147
    }
1✔
148

149
    /**
150
     * Creates the parameters.
151
     *
152
     * @param rootDir
153
     *            the root dir
154
     * @param cssFiles
155
     *            the css files
156
     * @param outputDir
157
     *            the output dir
158
     * @param documentRootDir
159
     *            the document root dir
160
     * @param logLevel
161
     *            the log level
162
     * @param cssFileSuffix
163
     *            the css file suffix
164
     * @param spritePngDepth
165
     *            the sprite png depth
166
     * @param cssEncoding
167
     *            the css encoding
168
     */
169
    public SmartSpritesParameters(String rootDir, List<String> cssFiles, String outputDir, String documentRootDir,
170
            MessageLevel logLevel, String cssFileSuffix, PngDepth spritePngDepth, String cssEncoding) {
171
        this(rootDir, cssFiles, outputDir, documentRootDir, logLevel, cssFileSuffix, spritePngDepth, cssEncoding,
1✔
172
                DEFAULT_MARK_SPRITE_IMAGES);
173
    }
1✔
174

175
    /**
176
     * Creates the parameters.
177
     *
178
     * @param rootDir
179
     *            the root dir
180
     * @param cssFiles
181
     *            the css files
182
     * @param outputDir
183
     *            the output dir
184
     * @param documentRootDir
185
     *            the document root dir
186
     * @param logLevel
187
     *            the log level
188
     * @param cssFileSuffix
189
     *            the css file suffix
190
     * @param spritePngDepth
191
     *            the sprite png depth
192
     * @param cssEncoding
193
     *            the css encoding
194
     * @param markSpriteImages
195
     *            the mark sprite images
196
     */
197
    public SmartSpritesParameters(String rootDir, List<String> cssFiles, String outputDir, String documentRootDir,
198
            MessageLevel logLevel, String cssFileSuffix, PngDepth spritePngDepth, String cssEncoding,
199
            boolean markSpriteImages) {
1✔
200
        this.rootDir = rootDir;
1✔
201
        this.cssFiles = cssFiles;
1✔
202
        this.outputDir = outputDir;
1✔
203
        this.documentRootDir = documentRootDir;
1✔
204
        this.logLevel = logLevel;
1✔
205
        this.cssFileEncoding = cssEncoding;
1✔
206
        this.cssFileSuffix = getCssFileSuffix(cssFileSuffix);
1✔
207
        this.spritePngDepth = spritePngDepth;
1✔
208
        this.markSpriteImages = markSpriteImages;
1✔
209
    }
1✔
210

211
    /**
212
     * Validates the provided parameters. All resource paths are resolved against the local file system.
213
     *
214
     * @param log
215
     *            the log
216
     *
217
     * @return <code>true</code> if the parameters are valid
218
     */
219
    public boolean validate(MessageLog log) {
220
        boolean valid = true;
1✔
221

222
        // Either root dir or css files are required
223
        if (!hasRootDir() && !hasCssFiles()) {
1✔
224
            log.error(MessageType.EITHER_ROOT_DIR_OR_CSS_FILES_IS_REQUIRED);
1✔
225
            return false;
1✔
226
        }
227

228
        // If there is no output dir, we can't have both root dir or css files
229
        if (!hasOutputDir() && hasRootDir() && hasCssFiles()) {
1✔
230
            log.error(MessageType.ROOT_DIR_AND_CSS_FILES_CANNOT_BE_BOTH_SPECIFIED_UNLESS_WITH_OUTPUT_DIR);
1✔
231
            return false;
1✔
232
        }
233

234
        // Check root dir if provided
235
        if (hasRootDir()) {
1✔
236
            final File directory = FileUtils.getCanonicalOrAbsoluteFile(this.rootDir);
1✔
237
            if (!directory.exists() || !directory.isDirectory()) {
1!
238
                log.error(MessageType.ROOT_DIR_DOES_NOT_EXIST_OR_IS_NOT_DIRECTORY, this.rootDir);
1✔
239
                valid = false;
1✔
240
            }
241
        }
242

243
        // Check output dir if provided
244
        if (hasOutputDir()) {
1✔
245
            // For output dir, we need root dir
246
            if (!hasRootDir()) {
1✔
247
                log.error(MessageType.ROOT_DIR_IS_REQUIRED_FOR_OUTPUT_DIR);
1✔
248
                return false;
1✔
249
            }
250

251
            final File directory = FileUtils.getCanonicalOrAbsoluteFile(this.outputDir);
1✔
252
            if (directory.exists() && !directory.isDirectory()) {
1✔
253
                log.error(MessageType.OUTPUT_DIR_IS_NOT_DIRECTORY, this.outputDir);
1✔
254
                valid = false;
1✔
255
            }
256
        }
257

258
        if (!hasOutputDir() && StringUtils.isBlank(cssFileSuffix)) {
1✔
259
            log.error(MessageType.CSS_FILE_SUFFIX_IS_REQUIRED_IF_NO_OUTPUT_DIR);
1✔
260
            valid = false;
1✔
261
        }
262

263
        if (hasDocumentRootDir()) {
1✔
264
            final File directory = FileUtils.getCanonicalOrAbsoluteFile(this.documentRootDir);
1✔
265
            if (!directory.exists() || !directory.isDirectory()) {
1✔
266
                log.error(MessageType.DOCUMENT_ROOT_DIR_DOES_NOT_EXIST_OR_IS_NOT_DIRECTORY, this.documentRootDir);
1✔
267
                valid = false;
1✔
268
            }
269
        }
270

271
        return valid;
1✔
272
    }
273

274
    /**
275
     * Gets the css file suffix.
276
     *
277
     * @param suffix
278
     *            the suffix
279
     *
280
     * @return the css file suffix
281
     */
282
    private String getCssFileSuffix(String suffix) {
283
        if (suffix != null) {
1✔
284
            return suffix;
1✔
285
        }
286
        if (!hasOutputDir()) {
1✔
287
            // If there is no output dir, we must have some suffix
288
            return DEFAULT_CSS_FILE_SUFFIX;
1✔
289
        }
290
        // If we have an output dir, we can have an empty suffix
291
        return "";
1✔
292
    }
293

294
    /**
295
     * Gets the root dir.
296
     *
297
     * @return the root dir
298
     */
299
    public String getRootDir() {
300
        return rootDir;
1✔
301
    }
302

303
    /**
304
     * Gets the root dir file.
305
     *
306
     * @return the root dir file
307
     *
308
     * @throws IOException
309
     *             Signals that an I/O exception has occurred.
310
     */
311
    public File getRootDirFile() throws IOException {
312
        return rootDir.startsWith("..") ? Path.of(rootDir).toFile().getCanonicalFile() : Path.of(rootDir).toFile();
1!
313
    }
314

315
    /**
316
     * Checks for root dir.
317
     *
318
     * @return true, if successful
319
     */
320
    public boolean hasRootDir() {
321
        return StringUtils.isNotBlank(rootDir);
1✔
322
    }
323

324
    /**
325
     * Gets the css files.
326
     *
327
     * @return the css files
328
     */
329
    public List<String> getCssFiles() {
330
        return cssFiles;
1✔
331
    }
332

333
    /**
334
     * Checks for css files.
335
     *
336
     * @return true, if successful
337
     */
338
    public boolean hasCssFiles() {
339
        return cssFiles != null && !cssFiles.isEmpty();
1!
340
    }
341

342
    /**
343
     * Gets the output dir.
344
     *
345
     * @return the output dir
346
     */
347
    public String getOutputDir() {
348
        return outputDir;
1✔
349
    }
350

351
    /**
352
     * Checks for output dir.
353
     *
354
     * @return true, if successful
355
     */
356
    public boolean hasOutputDir() {
357
        return StringUtils.isNotBlank(outputDir);
1✔
358
    }
359

360
    /**
361
     * Gets the document root dir.
362
     *
363
     * @return the document root dir
364
     */
365
    public String getDocumentRootDir() {
366
        return documentRootDir;
1✔
367
    }
368

369
    /**
370
     * Checks for document root dir.
371
     *
372
     * @return true, if successful
373
     */
374
    public boolean hasDocumentRootDir() {
375
        return StringUtils.isNotBlank(documentRootDir);
1✔
376
    }
377

378
    /**
379
     * Gets the log level.
380
     *
381
     * @return the log level
382
     */
383
    public MessageLevel getLogLevel() {
384
        return logLevel;
×
385
    }
386

387
    /**
388
     * Gets the css file suffix.
389
     *
390
     * @return the css file suffix
391
     */
392
    public String getCssFileSuffix() {
393
        return cssFileSuffix;
1✔
394
    }
395

396
    /**
397
     * Gets the sprite png depth.
398
     *
399
     * @return the sprite png depth
400
     */
401
    public PngDepth getSpritePngDepth() {
402
        return spritePngDepth;
1✔
403
    }
404

405
    /**
406
     * Checks if is mark sprite images.
407
     *
408
     * @return true, if is mark sprite images
409
     */
410
    public boolean isMarkSpriteImages() {
411
        return markSpriteImages;
1✔
412
    }
413

414
    /**
415
     * Gets the css file encoding.
416
     *
417
     * @return the css file encoding
418
     */
419
    public String getCssFileEncoding() {
420
        return cssFileEncoding;
1✔
421
    }
422
}
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