View Javadoc
1   /*
2    * SPDX-FileCopyrightText: Copyright (c) 2011-2026 Yegor Bugayenko
3    * SPDX-License-Identifier: MIT
4    */
5   package com.qulice.checkstyle;
6   
7   import com.qulice.spi.Environment;
8   import com.qulice.spi.Violation;
9   import java.io.File;
10  import java.io.IOException;
11  import java.util.Collection;
12  import org.cactoos.text.IoCheckedText;
13  import org.cactoos.text.Joined;
14  import org.hamcrest.MatcherAssert;
15  import org.hamcrest.Matchers;
16  import org.junit.jupiter.api.Test;
17  
18  /**
19   * Test case for {@link CheckstyleValidator} covering checks that apply to
20   * non-Java text files and whitespace before closing braces.
21   * @since 0.25.0
22   */
23  final class CheckstyleTextFileTest {
24  
25      /**
26       * Name of property to set to change location of the license.
27       */
28      private static final String LICENSE_PROP = "license";
29  
30      /**
31       * Directory with classes.
32       */
33      private static final String DIRECTORY = "src/main/java/foo";
34  
35      /**
36       * License text.
37       */
38      private static final String LICENSE = "Hello.";
39  
40      /**
41       * CheckstyleValidator reports a tab character in a non-Java text file
42       * such as JavaScript. See https://github.com/yegor256/qulice/issues/521.
43       * @throws Exception when error.
44       */
45      @Test
46      void rejectsTabInNonJavaTextFile() throws Exception {
47          final String file = "script.js";
48          MatcherAssert.assertThat(
49              "Tab character in .js file is not reported",
50              this.runValidationWithContent(
51                  file,
52                  "\tconsole.log(\"Hello World\");".concat(String.valueOf('\n'))
53              ),
54              Matchers.hasItem(
55                  new ViolationMatcher(
56                      "tab", file, "1", "FileTabCharacterCheck"
57                  )
58              )
59          );
60      }
61  
62      /**
63       * CheckstyleValidator reports missing final newline in a non-Java text
64       * file such as Markdown. See https://github.com/yegor256/qulice/issues/521.
65       * @throws Exception when error.
66       */
67      @Test
68      void rejectsMissingNewlineInNonJavaTextFile() throws Exception {
69          final String file = "README.md";
70          MatcherAssert.assertThat(
71              "Missing final newline in .md file is not reported",
72              this.runValidationWithContent(
73                  file,
74                  "# Title".concat(String.valueOf('\n')).concat("No newline at end")
75              ),
76              Matchers.hasItem(
77                  new ViolationMatcher(
78                      "File does not end with a newline.", file, "",
79                      "NewlineAtEndOfFileCheck"
80                  )
81              )
82          );
83      }
84  
85      /**
86       * CheckstyleValidator rejects empty lines before closing braces.
87       * See https://github.com/yegor256/qulice/issues/710.
88       * @throws Exception when error.
89       */
90      @Test
91      void rejectsEmptyLineBeforeClosingBrace() throws Exception {
92          final String file = "EmptyLineBeforeBrace.java";
93          MatcherAssert.assertThat(
94              "Empty line before closing brace is not reported",
95              this.runValidationWithContent(
96                  file,
97                  new IoCheckedText(
98                      new Joined(
99                          String.valueOf('\n'),
100                         "package foo;",
101                         "public final class EmptyLineBeforeBrace {",
102                         "    public void foo() {",
103                         "        int x = 1;",
104                         "",
105                         "    }",
106                         "}",
107                         ""
108                     )
109                 ).asString()
110             ),
111             Matchers.hasItem(
112                 new ViolationMatcher(
113                     "Empty line before closing brace is not allowed",
114                     file, "", "RegexpMultilineCheck"
115                 )
116             )
117         );
118     }
119 
120     /**
121      * CheckstyleValidator does not report a false positive when a closing
122      * brace immediately follows a non-empty line.
123      * See https://github.com/yegor256/qulice/issues/710.
124      * @throws Exception when error.
125      */
126     @Test
127     void acceptsNoEmptyLineBeforeClosingBrace() throws Exception {
128         final String file = "NoEmptyLineBeforeBrace.java";
129         MatcherAssert.assertThat(
130             "Absence of empty line before closing brace was reported",
131             this.runValidationWithContent(
132                 file,
133                 new IoCheckedText(
134                     new Joined(
135                         String.valueOf('\n'),
136                         "package foo;",
137                         "public final class NoEmptyLineBeforeBrace {",
138                         "    public void foo() {",
139                         "        int x = 1;",
140                         "    }",
141                         "}",
142                         ""
143                     )
144                 ).asString()
145             ),
146             Matchers.not(
147                 Matchers.hasItem(
148                     new ViolationMatcher(
149                         "Empty line before closing brace is not allowed",
150                         file, "", "RegexpMultilineCheck"
151                     )
152                 )
153             )
154         );
155     }
156 
157     /**
158      * Runs Checkstyle validation over a file whose content is supplied
159      * in-place (as opposed to loaded from a resource).
160      * @param file Name of the file to check
161      * @param content Bytes to write as the file content
162      * @return Violations reported by the validator
163      * @throws IOException If some IO problem
164      */
165     private Collection<Violation> runValidationWithContent(final String file,
166         final String content) throws IOException {
167         final Environment.Mock mock = new Environment.Mock();
168         final Environment env = mock.withParam(
169             CheckstyleTextFileTest.LICENSE_PROP,
170             String.format(
171                 "file:%s",
172                 new License().savePackageInfo(
173                     new File(mock.basedir(), CheckstyleTextFileTest.DIRECTORY)
174                 ).withLines(CheckstyleTextFileTest.LICENSE)
175                     .withEol(String.valueOf('\n')).file()
176             )
177         ).withFile(String.format("src/main/resources/%s", file), content);
178         return new CheckstyleValidator(env).validate(env.files(file));
179     }
180 }