Skip to content

Commit fead434

Browse files
committed
Fix #88 Add exclusions on font-family-not-ending-with-generic-font-family for icon fonts
1 parent a574501 commit fead434

File tree

11 files changed

+159
-5
lines changed

11 files changed

+159
-5
lines changed

.travis.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
sudo: required
2+
13
language: java
24

35
jdk:

css-checks/src/main/java/org/sonar/css/checks/common/FontFamilyNotEndingWithGenericFontFamilyCheck.java

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,34 @@
1919
*/
2020
package org.sonar.css.checks.common;
2121

22+
import com.google.common.annotations.VisibleForTesting;
2223
import org.sonar.check.Priority;
2324
import org.sonar.check.Rule;
25+
import org.sonar.check.RuleProperty;
26+
import org.sonar.css.checks.CheckList;
27+
import org.sonar.css.checks.CheckUtils;
2428
import org.sonar.css.checks.Tags;
2529
import org.sonar.css.model.atrule.standard.FontFace;
2630
import org.sonar.css.model.property.StandardProperty;
2731
import org.sonar.css.model.property.standard.FontFamily;
2832
import org.sonar.css.tree.impl.SeparatedList;
2933
import org.sonar.plugins.css.api.tree.Tree;
30-
import org.sonar.plugins.css.api.tree.css.*;
34+
import org.sonar.plugins.css.api.tree.css.AtRuleTree;
35+
import org.sonar.plugins.css.api.tree.css.DelimiterTree;
36+
import org.sonar.plugins.css.api.tree.css.IdentifierTree;
37+
import org.sonar.plugins.css.api.tree.css.PropertyDeclarationTree;
38+
import org.sonar.plugins.css.api.tree.css.StringTree;
39+
import org.sonar.plugins.css.api.tree.css.ValueCommaSeparatedListTree;
40+
import org.sonar.plugins.css.api.tree.css.ValueTree;
3141
import org.sonar.plugins.css.api.visitors.DoubleDispatchVisitorCheck;
3242
import org.sonar.squidbridge.annotations.ActivatedByDefault;
3343
import org.sonar.squidbridge.annotations.SqaleConstantRemediation;
3444

3545
import javax.annotation.Nullable;
46+
import java.text.MessageFormat;
3647
import java.util.List;
48+
import java.util.regex.Pattern;
49+
import java.util.regex.PatternSyntaxException;
3750

3851
@Rule(
3952
key = "font-family-not-ending-with-generic-font-family",
@@ -44,6 +57,16 @@
4457
@ActivatedByDefault
4558
public class FontFamilyNotEndingWithGenericFontFamilyCheck extends DoubleDispatchVisitorCheck {
4659

60+
private static final String DEFAULT_EXCLUSIONS = "(?i)^(FontAwesome|Glyphicons Halflings|Ionicons|Genericons)$";
61+
@RuleProperty(
62+
key = "Exclusions",
63+
description = "Regular expression of font families to exclude. See "
64+
+ CheckUtils.LINK_TO_JAVA_REGEX_PATTERN_DOC
65+
+ " for detailed regular expression syntax.",
66+
defaultValue = DEFAULT_EXCLUSIONS)
67+
private String exclusions = DEFAULT_EXCLUSIONS;
68+
69+
4770
@Override
4871
public void visitPropertyDeclaration(PropertyDeclarationTree tree) {
4972
if (propertyToBeChecked(tree)) {
@@ -85,18 +108,24 @@ private boolean isPotentialGenericFamily(@Nullable Tree tree) {
85108
return false;
86109
}
87110

88-
if (!tree.is(Tree.Kind.IDENTIFIER, Tree.Kind.LESS_VARIABLE, Tree.Kind.SCSS_VARIABLE, Tree.Kind.VARIABLE, Tree.Kind.FUNCTION)) {
111+
if (!tree.is(Tree.Kind.IDENTIFIER, Tree.Kind.STRING, Tree.Kind.LESS_VARIABLE, Tree.Kind.SCSS_VARIABLE, Tree.Kind.VARIABLE, Tree.Kind.FUNCTION)) {
89112
return false;
90113
}
91114

92115
if (tree.is(Tree.Kind.IDENTIFIER)) {
93116
IdentifierTree identifier = (IdentifierTree) tree;
94117
if (!identifier.isInterpolated()
95118
&& !FontFamily.GENERIC_FAMILY_NAMES.contains(identifier.text().toLowerCase())
96-
&& !StandardProperty.COMMON_VALUES.contains(identifier.text().toLowerCase())) {
119+
&& !StandardProperty.COMMON_VALUES.contains(identifier.text().toLowerCase())
120+
&& !identifier.text().matches(exclusions)) {
97121
return false;
98122
}
99123
}
124+
125+
if (tree.is(Tree.Kind.STRING) && !((StringTree) tree).actualText().matches(exclusions)) {
126+
return false;
127+
}
128+
100129
return true;
101130
}
102131

@@ -115,4 +144,25 @@ private boolean propertyToBeChecked(PropertyDeclarationTree tree) {
115144
return true;
116145
}
117146

147+
@VisibleForTesting
148+
void setExclusions(String exclusions) {
149+
this.exclusions = exclusions;
150+
}
151+
152+
@Override
153+
public void validateParameters() {
154+
try {
155+
Pattern.compile(exclusions);
156+
} catch (PatternSyntaxException exception) {
157+
throw new IllegalStateException(paramsErrorMessage(), exception);
158+
}
159+
}
160+
161+
private String paramsErrorMessage() {
162+
return CheckUtils.paramsErrorMessage(
163+
this.getClass(),
164+
CheckList.CSS_REPOSITORY_KEY,
165+
MessageFormat.format("exclusions parameter \"{0}\" is not a valid regular expression.", exclusions));
166+
}
167+
118168
}

css-checks/src/test/java/org/sonar/css/checks/common/FontFamilyNotEndingWithGenericFontFamilyCheckTest.java

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,25 +25,55 @@
2525

2626
import java.io.File;
2727

28-
public class FontFamilyNotEndingWithGenericFontFamilyCheckTest {
28+
import static org.fest.assertions.Assertions.assertThat;
2929

30-
private FontFamilyNotEndingWithGenericFontFamilyCheck check = new FontFamilyNotEndingWithGenericFontFamilyCheck();
30+
public class FontFamilyNotEndingWithGenericFontFamilyCheckTest {
3131

3232
@Test
3333
public void test_css() {
34+
FontFamilyNotEndingWithGenericFontFamilyCheck check = new FontFamilyNotEndingWithGenericFontFamilyCheck();
3435
CssCheckVerifier.verifyCssFile(check, getTestFile("fontFamilyNotEndingWithGenericFontFamily.css"));
3536
}
3637

3738
@Test
3839
public void test_less() {
40+
FontFamilyNotEndingWithGenericFontFamilyCheck check = new FontFamilyNotEndingWithGenericFontFamilyCheck();
3941
CssCheckVerifier.verifyLessFile(check, getTestFile("fontFamilyNotEndingWithGenericFontFamily.less"));
4042
}
4143

4244
@Test
4345
public void test_scss() {
46+
FontFamilyNotEndingWithGenericFontFamilyCheck check = new FontFamilyNotEndingWithGenericFontFamilyCheck();
4447
CssCheckVerifier.verifyScssFile(check, getTestFile("fontFamilyNotEndingWithGenericFontFamily.scss"));
4548
}
4649

50+
@Test
51+
public void test_with_default_exclusions() {
52+
FontFamilyNotEndingWithGenericFontFamilyCheck check = new FontFamilyNotEndingWithGenericFontFamilyCheck();
53+
CssCheckVerifier.verifyCssFile(check, getTestFile("fontFamilyNotEndingWithGenericFontFamilyDefaultExclusions.css"));
54+
}
55+
56+
@Test
57+
public void test_with_custom_format() {
58+
FontFamilyNotEndingWithGenericFontFamilyCheck check = new FontFamilyNotEndingWithGenericFontFamilyCheck();
59+
check.setExclusions("^My-.+$");
60+
CssCheckVerifier.verifyCssFile(check, getTestFile("fontFamilyNotEndingWithGenericFontFamilyCustomExclusions.css"));
61+
}
62+
63+
@Test
64+
public void should_throw_an_illegal_state_exception_as_the_exclusions_parameter_is_not_valid() {
65+
try {
66+
FontFamilyNotEndingWithGenericFontFamilyCheck check = new FontFamilyNotEndingWithGenericFontFamilyCheck();
67+
check.setExclusions("(");
68+
69+
CssCheckVerifier.issuesOnCssFile(check, getTestFile("fontFamilyNotEndingWithGenericFontFamily.css")).noMore();
70+
71+
} catch (IllegalStateException e) {
72+
assertThat(e.getMessage()).isEqualTo("Check css:font-family-not-ending-with-generic-font-family (font-family properties should end with a generic font family): "
73+
+ "exclusions parameter \"(\" is not a valid regular expression.");
74+
}
75+
}
76+
4777
private File getTestFile(String fileName) {
4878
return CheckTestUtils.getCommonTestFile("font-family-not-ending-with-generic-font-family/" + fileName);
4979
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.mybox1 {
2+
font-family: FontAwesome; /* Noncompliant ![sc=16;ec=27;el=+0]! !{Add a generic font family at the end of the declaration.}! */
3+
font-family: My-Icons;
4+
font-family: my-icons; /* Noncompliant ![sc=16;ec=24;el=+0]! !{Add a generic font family at the end of the declaration.}! */
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.mybox1 {
2+
font-family: FontAwesome;
3+
font-family: "FontAwesome";
4+
font-family: "Glyphicons Halflings";
5+
font-family: Ionicons;
6+
font-family: "Ionicons";
7+
font-family: Genericons;
8+
font-family: "Genericons";
9+
font-family: genericons;
10+
font-family: "genericons";
11+
font-family: MyIcons; /* Noncompliant ![sc=16;ec=23;el=+0]! !{Add a generic font family at the end of the declaration.}! */
12+
font-family: "MyIcons"; /* Noncompliant ![sc=16;ec=25;el=+0]! !{Add a generic font family at the end of the declaration.}! */
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.mybox1 {
2+
font-family: FontAwesome; /* Noncompliant ![sc=16;ec=27;el=+0]! !{Add a generic font family at the end of the declaration.}! */
3+
font-family: My-Icons;
4+
font-family: my-icons; /* Noncompliant ![sc=16;ec=24;el=+0]! !{Add a generic font family at the end of the declaration.}! */
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.mybox1 {
2+
font-family: FontAwesome;
3+
font-family: "FontAwesome";
4+
font-family: "Glyphicons Halflings";
5+
font-family: Ionicons;
6+
font-family: "Ionicons";
7+
font-family: Genericons;
8+
font-family: "Genericons";
9+
font-family: genericons;
10+
font-family: "genericons";
11+
font-family: MyIcons; /* Noncompliant ![sc=16;ec=23;el=+0]! !{Add a generic font family at the end of the declaration.}! */
12+
font-family: "MyIcons"; /* Noncompliant ![sc=16;ec=25;el=+0]! !{Add a generic font family at the end of the declaration.}! */
13+
}

its/ruling/tests/src/test/expected/css-font-family-not-ending-with-generic-font-family.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@
1414
11,
1515
12,
1616
],
17+
'project:custom/common/font-family-not-ending-with-generic-font-family/fontFamilyNotEndingWithGenericFontFamilyCustomExclusions.css':[
18+
3,
19+
4,
20+
],
21+
'project:custom/common/font-family-not-ending-with-generic-font-family/fontFamilyNotEndingWithGenericFontFamilyDefaultExclusions.css':[
22+
11,
23+
12,
24+
],
1725
'project:custom/common/formatting/delimiterSeparatedList.css':[
1826
2,
1927
],

its/ruling/tests/src/test/expected/css-line-length.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,14 @@
8484
11,
8585
12,
8686
],
87+
'project:custom/common/font-family-not-ending-with-generic-font-family/fontFamilyNotEndingWithGenericFontFamilyCustomExclusions.css':[
88+
2,
89+
4,
90+
],
91+
'project:custom/common/font-family-not-ending-with-generic-font-family/fontFamilyNotEndingWithGenericFontFamilyDefaultExclusions.css':[
92+
11,
93+
12,
94+
],
8795
'project:custom/common/fontface/basic.css':[
8896
58,
8997
63,

its/ruling/tests/src/test/expected/css-single-quotes.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@
3030
'project:custom/common/font-family-not-ending-with-generic-font-family/fontFamilyNotEndingWithGenericFontFamily.css':[
3131
6,
3232
],
33+
'project:custom/common/font-family-not-ending-with-generic-font-family/fontFamilyNotEndingWithGenericFontFamilyDefaultExclusions.css':[
34+
3,
35+
4,
36+
6,
37+
8,
38+
10,
39+
12,
40+
],
3341
'project:custom/common/known-properties/knownProperties.css':[
3442
38,
3543
68,

0 commit comments

Comments
 (0)