1 /*
2  * Copyright 2014 - 2020 Rafael Winterhalter
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package net.bytebuddy.matcher;
17
18 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
19 import net.bytebuddy.build.HashCodeAndEqualsPlugin;
20
21 /**
22  * An element matcher that compares two strings by a given pattern which is characterized by a
23  * {@link net.bytebuddy.matcher.StringMatcher.Mode}.
24  */

25 @HashCodeAndEqualsPlugin.Enhance
26 public class StringMatcher extends ElementMatcher.Junction.AbstractBase<String> {
27
28     /**
29      * The text value to match against.
30      */

31     private final String value;
32
33     /**
34      * The mode to apply for matching the given value against the matcher's input.
35      */

36     private final Mode mode;
37
38     /**
39      * Creates a new string matcher.
40      *
41      * @param value The value that is the base of the matching.
42      * @param mode  The mode to apply for matching the given value against the matcher's input
43      */

44     public StringMatcher(String value, Mode mode) {
45         this.value = value;
46         this.mode = mode;
47     }
48
49     /**
50      * {@inheritDoc}
51      */

52     public boolean matches(String target) {
53         return mode.matches(value, target);
54     }
55
56     @Override
57     public String toString() {
58         return mode.getDescription() + '(' + value + ')';
59     }
60
61     /**
62      * Defines the mode a {@link net.bytebuddy.matcher.StringMatcher} compares to strings with.
63      */

64     public enum Mode {
65
66         /**
67          * Checks if two strings equal and respects casing differences.
68          */

69         EQUALS_FULLY("equals") {
70             @Override
71             protected boolean matches(String expected, String actual) {
72                 return actual.equals(expected);
73             }
74         },
75
76         /**
77          * Checks if two strings equal without respecting casing differences.
78          */

79         EQUALS_FULLY_IGNORE_CASE("equalsIgnoreCase") {
80             @Override
81             protected boolean matches(String expected, String actual) {
82                 return actual.equalsIgnoreCase(expected);
83             }
84         },
85
86         /**
87          * Checks if a string starts with the a second string with respecting casing differences.
88          */

89         STARTS_WITH("startsWith") {
90             @Override
91             protected boolean matches(String expected, String actual) {
92                 return actual.startsWith(expected);
93             }
94         },
95
96         /**
97          * Checks if a string starts with a second string without respecting casing differences.
98          */

99         STARTS_WITH_IGNORE_CASE("startsWithIgnoreCase") {
100             @Override
101             @SuppressFBWarnings(value = "DM_CONVERT_CASE", justification = "Both strings are transformed by the default locale")
102             protected boolean matches(String expected, String actual) {
103                 return actual.toLowerCase().startsWith(expected.toLowerCase());
104             }
105         },
106
107         /**
108          * Checks if a string ends with a second string with respecting casing differences.
109          */

110         ENDS_WITH("endsWith") {
111             @Override
112             protected boolean matches(String expected, String actual) {
113                 return actual.endsWith(expected);
114             }
115         },
116
117         /**
118          * Checks if a string ends with a second string without respecting casing differences.
119          */

120         ENDS_WITH_IGNORE_CASE("endsWithIgnoreCase") {
121             @Override
122             @SuppressFBWarnings(value = "DM_CONVERT_CASE", justification = "Both strings are transformed by the default locale")
123             protected boolean matches(String expected, String actual) {
124                 return actual.toLowerCase().endsWith(expected.toLowerCase());
125             }
126         },
127
128         /**
129          * Checks if a string contains another string with respecting casing differences.
130          */

131         CONTAINS("contains") {
132             @Override
133             protected boolean matches(String expected, String actual) {
134                 return actual.contains(expected);
135             }
136         },
137
138         /**
139          * Checks if a string contains another string without respecting casing differences.
140          */

141         CONTAINS_IGNORE_CASE("containsIgnoreCase") {
142             @Override
143             @SuppressFBWarnings(value = "DM_CONVERT_CASE", justification = "Both strings are transformed by the default locale")
144             protected boolean matches(String expected, String actual) {
145                 return actual.toLowerCase().contains(expected.toLowerCase());
146             }
147         },
148
149         /**
150          * Checks if a string can be matched by a regular expression.
151          */

152         MATCHES("matches") {
153             @Override
154             protected boolean matches(String expected, String actual) {
155                 return actual.matches(expected);
156             }
157         };
158
159         /**
160          * A description of the string for providing meaningful {@link Object#toString()} implementations for
161          * method matchers that rely on a match mode.
162          */

163         private final String description;
164
165         /**
166          * Creates a new match mode.
167          *
168          * @param description The description of this mode for providing meaningful {@link Object#toString()}
169          *                    implementations.
170          */

171         Mode(String description) {
172             this.description = description;
173         }
174
175         /**
176          * Returns the description of this match mode.
177          *
178          * @return The description of this match mode.
179          */

180         protected String getDescription() {
181             return description;
182         }
183
184         /**
185          * Matches a string against another string.
186          *
187          * @param expected The target of the comparison against which the {@code actual} string is compared.
188          * @param actual   The source which is subject of the comparison to the {@code expected} value.
189          * @return {@code trueif the source matches the target.
190          */

191         protected abstract boolean matches(String expected, String actual);
192     }
193 }
194