View Javadoc
1   /*
2    * Copyright (c) 2012-2024, jcabi.com
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met: 1) Redistributions of source code must retain the above
8    * copyright notice, this list of conditions and the following
9    * disclaimer. 2) Redistributions in binary form must reproduce the above
10   * copyright notice, this list of conditions and the following
11   * disclaimer in the documentation and/or other materials provided
12   * with the distribution. 3) Neither the name of the jcabi.com nor
13   * the names of its contributors may be used to endorse or promote
14   * products derived from this software without specific prior written
15   * permission.
16   *
17   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
19   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21   * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28   * OF THE POSSIBILITY OF SUCH DAMAGE.
29   */
30  package com.jcabi.aspects;
31  
32  import java.lang.annotation.ElementType;
33  import java.lang.annotation.Retention;
34  import java.lang.annotation.RetentionPolicy;
35  import java.lang.annotation.Target;
36  import javax.validation.ConstraintViolationException;
37  import javax.validation.Valid;
38  import javax.validation.constraints.NotNull;
39  import javax.validation.constraints.Pattern;
40  import org.hamcrest.MatcherAssert;
41  import org.hamcrest.Matchers;
42  import org.junit.jupiter.api.Assertions;
43  import org.junit.jupiter.api.Disabled;
44  import org.junit.jupiter.api.Test;
45  
46  /**
47   * Test case for JSR-303 annotations and their implementations.
48   *
49   * <a href="https://beanvalidation.org/1.0/spec/"></a>
50   * @since 0.0.0
51   * @checkstyle AbbreviationAsWordInNameCheck (5 lines)
52   */
53  @SuppressWarnings("PMD.TooManyMethods")
54  final class JSR303Test {
55      /**
56       * The test message.
57       */
58      private static final String OVERRIDEN_MSG = "this is a message";
59  
60      @Test
61      void throwsWhenMethodParametersAreInvalid() {
62          Assertions.assertThrows(
63              ConstraintViolationException.class,
64              () -> new JSR303Test.Foo().foo(null)
65          );
66      }
67  
68      @Test
69      void throwsWhenRegularExpressionDoesntMatch() {
70          Assertions.assertThrows(
71              ConstraintViolationException.class,
72              () -> new JSR303Test.Foo().foo("some text")
73          );
74      }
75  
76      @Test
77      void passesWhenMethodParametersAreValid() {
78          new JSR303Test.Foo().foo("123");
79      }
80  
81      @Test
82      void validatesOutputForNonNull() {
83          Assertions.assertThrows(
84              ConstraintViolationException.class,
85              () -> new JSR303Test.Foo().nullValue()
86          );
87      }
88  
89      @Test
90      void ignoresVoidResponses() {
91          new JSR303Test.Foo().voidAlways();
92      }
93  
94      @Test
95      @Disabled
96      void validatesConstructorParameters() {
97          Assertions.assertThrows(
98              ConstraintViolationException.class,
99              () -> new JSR303Test.ConstructorValidation(null, null)
100         );
101     }
102 
103     @Test
104     @Disabled
105     void validatesChainedConstructorParameters() {
106         Assertions.assertThrows(
107             ConstraintViolationException.class,
108             () -> new JSR303Test.ConstructorValidation(null)
109         );
110     }
111 
112     @Test
113     void overridesMessage() {
114         MatcherAssert.assertThat(
115             Assertions.assertThrows(
116                 ConstraintViolationException.class,
117                 () -> new JSR303Test.Bar().test(null)
118             ),
119             Matchers.hasProperty(
120                 "message",
121                 Matchers.containsString(JSR303Test.OVERRIDEN_MSG)
122             )
123         );
124     }
125 
126     @Test
127     void skipsConstraintRule() {
128         new JSR303Test.Bar().test("value");
129     }
130 
131     /**
132      * Annotation.
133      * @since 0.0.0
134      */
135     @Retention(RetentionPolicy.RUNTIME)
136     @Target(ElementType.PARAMETER)
137     private @interface NoMeaning {
138     }
139 
140     /**
141      * Dummy interface for testing messages overriding.
142      * @since 0.0.0
143      */
144     private interface Fum {
145         /**
146          * Test method.
147          *
148          * @param value Value
149          */
150         void test(@NotNull(message = JSR303Test.OVERRIDEN_MSG) String value);
151     }
152 
153     /**
154      * Dummy class, for tests above.
155      * @since 0.0.0
156      */
157     @Loggable()
158     private static final class Foo {
159         /**
160          * Do nothing.
161          *
162          * @param text Some text
163          * @return Some data
164          */
165         @NotNull
166         public int foo(
167             @NotNull @Pattern(regexp = "\\d+")
168             @JSR303Test.NoMeaning final String text
169         ) {
170             return -1;
171         }
172 
173         /**
174          * Always return null.
175          *
176          * @return Some data
177          */
178         @NotNull
179         @Valid
180         public Integer nullValue() {
181             return null;
182         }
183 
184         /**
185          * Ignores when void.
186          */
187         public void voidAlways() {
188             // nothing to do
189         }
190     }
191 
192     /**
193      * Dummy class for testing constructor validation.
194      * @since 0.0.0
195      */
196     @Loggable()
197     private static final class ConstructorValidation {
198         /**
199          * Public ctor.
200          *
201          * @param first First param
202          * @param second Second param
203          * @checkstyle UnusedFormalParameter (3 lines)
204          */
205         @SuppressWarnings("PMD.UnusedFormalParameter")
206         private ConstructorValidation(
207             @NotNull final String first,
208             @NotNull final String second
209         ) {
210             //Nothing to do.
211         }
212 
213         /**
214          * Public ctor.
215          *
216          * @param param The param.
217          */
218         private ConstructorValidation(@NotNull final String param) {
219             this(param, "foo");
220         }
221     }
222 
223     /**
224      * Dummy class for testing messages overriding.
225      *
226      * @since 0.0.0
227      */
228     @Loggable()
229     private static class Bar implements JSR303Test.Fum {
230         @Override
231         public void test(@NotNull final String value) {
232             //Nothing to do.
233         }
234     }
235 
236 }