001/**
002 * Powerunit - A JDK1.8 test framework
003 * Copyright (C) 2014 Mathieu Boretti.
004 *
005 * This file is part of Powerunit
006 *
007 * Powerunit is free software: you can redistribute it and/or modify
008 * it under the terms of the GNU General Public License as published by
009 * the Free Software Foundation, either version 3 of the License, or
010 * (at your option) any later version.
011 *
012 * Powerunit is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
015 * GNU General Public License for more details.
016 *
017 * You should have received a copy of the GNU General Public License
018 * along with Powerunit. If not, see <http://www.gnu.org/licenses/>.
019 */
020package ch.powerunit.pattern;
021
022import java.util.ArrayList;
023import java.util.Collections;
024import java.util.List;
025import java.util.Objects;
026import java.util.regex.Pattern;
027
028import org.hamcrest.Matcher;
029
030import ch.powerunit.TestInterface;
031import ch.powerunit.TestSuite;
032import ch.powerunit.pattern.impl.PatternTesterImpl;
033import ch.powerunit.pattern.lang.PatternTester0;
034import ch.powerunit.pattern.lang.PatternTester1;
035import ch.powerunit.pattern.lang.PatternTester2;
036import ch.powerunit.pattern.lang.PatternTester3;
037import ch.powerunit.pattern.lang.PatternTester4;
038
039/**
040 * This is a tester to validate {@link Pattern}.
041 * <p>
042 * This tester will validate that a Pattern accept (
043 * {@link Pattern#matcher(CharSequence)}) or not a specified string ; In the
044 * first case (accepted), it also provide a way to validate the groups (
045 * {@link java.util.regex.Matcher#group(int)}).
046 * 
047 * @author borettim
048 * @since 0.4.0
049 */
050@TestInterface(PatternTesterImpl.class)
051public final class PatternTester {
052        private final Pattern underTest;
053
054        private final List<String> inputs;
055
056        private final List<Boolean> expectedResult;
057
058        private final List<List<Integer>> havingGroup;
059
060        private final List<List<Matcher<String>>> expectedGroup;
061
062        private PatternTester(Pattern underTest, List<String> inputs,
063                        List<Boolean> expectedResult, List<List<Integer>> havingGroup,
064                        List<List<Matcher<String>>> expectedGroup) {
065                this.underTest = underTest;
066                this.inputs = inputs;
067                this.expectedResult = expectedResult;
068                this.havingGroup = havingGroup;
069                this.expectedGroup = expectedGroup;
070        }
071
072        /**
073         * Start the DSL to create a tester of Pattern, based on a String.
074         * <p>
075         * The passed String will be compiled as a Pattern. <br>
076         * For instance :
077         * 
078         * <pre>
079         * &#064;TestDelegate
080         * public final PatternTester sample1 = PatternTester.of(&quot;a+&quot;).receiving(&quot;b&quot;)
081         *              .thenNoMatching().receiving(&quot;aa&quot;).thenMatching().build();
082         * </pre>
083         * 
084         * @param pattern
085         *            the pattern, as a String
086         * @return {@link PatternTester0#receiving(String) The next step of the
087         *         DSL.}
088         * @see #of(Pattern)
089         */
090        public static PatternTester0 of(String pattern) {
091                return of(Pattern.compile(pattern));
092        }
093
094        /**
095         * Start the DSL to create a tester of Pattern, based on a String.
096         * <p>
097         * For instance :
098         * 
099         * <pre>
100         * &#064;TestDelegate
101         * public final PatternTester sample1 = PatternTester.of(Pattern.compile(&quot;a+&quot;))
102         *              .receiving(&quot;b&quot;).thenNoMatching().receiving(&quot;aa&quot;).thenMatching().build();
103         * </pre>
104         * 
105         * @param pattern
106         *            the pattern.
107         * @return {@link PatternTester0#receiving(String) The next step of the
108         *         DSL.}
109         */
110        public static PatternTester0 of(Pattern pattern) {
111                return new PatternTesterDSL(pattern);
112        }
113
114        private static class PatternTesterDSL implements PatternTester0,
115                        PatternTester1, PatternTester2, PatternTester3, PatternTester4 {
116
117                private final Pattern underTest;
118
119                private final List<String> inputs = new ArrayList<>();
120
121                private final List<Boolean> expectedResult = new ArrayList<>();
122
123                private final List<List<Integer>> havingGroup = new ArrayList<>();
124
125                private final List<List<Matcher<String>>> expectedGroup = new ArrayList<>();
126
127                private List<Integer> currentGroup = null;
128
129                private List<Matcher<String>> currentExpected = null;
130
131                private PatternTesterDSL initMatching(boolean expected) {
132                        expectedResult.add(expected);
133                        currentGroup = new ArrayList<>();
134                        currentExpected = new ArrayList<>();
135                        havingGroup.add(Collections.unmodifiableList(currentGroup));
136                        expectedGroup.add(Collections.unmodifiableList(currentExpected));
137                        return this;
138                }
139
140                /**
141                 * @param underTest
142                 */
143                private PatternTesterDSL(Pattern underTest) {
144                        this.underTest = underTest;
145                }
146
147                @Override
148                public PatternTester2 receiving(String input) {
149                        inputs.add(Objects.requireNonNull(input, "input can't be null"));
150                        return this;
151                }
152
153                @Override
154                public PatternTester1 thenNoMatching() {
155                        return initMatching(false);
156                }
157
158                @Override
159                public PatternTester3 thenMatching() {
160                        return initMatching(true);
161                }
162
163                @Override
164                public PatternTester4 havingGroup(int number) {
165                        if (number < 0) {
166                                throw new IllegalArgumentException("Number can't be <0");
167                        }
168                        currentGroup.add(number);
169                        return this;
170                }
171
172                @Override
173                public PatternTester3 matching(Matcher<String> matching) {
174                        currentExpected.add(Objects.requireNonNull(matching,
175                                        "matching can't be null"));
176                        return this;
177                }
178
179                @Override
180                public PatternTester3 equalTo(String equalTo) {
181                        return matching(TestSuite.DSL.equalTo(Objects.requireNonNull(
182                                        equalTo, "equalTo can't be null")));
183                }
184
185                @Override
186                public PatternTester build() {
187                        return new PatternTester(underTest, inputs, expectedResult,
188                                        havingGroup, expectedGroup);
189                }
190
191        }
192
193        /**
194         * Used by the framework.
195         * 
196         * @return the underTest
197         */
198        public Pattern getUnderTest() {
199                return underTest;
200        }
201
202        /**
203         * Used by the framework.
204         * 
205         * @return the inputs
206         */
207        public List<String> getInputs() {
208                return Collections.unmodifiableList(inputs);
209        }
210
211        /**
212         * Used by the framework.
213         * 
214         * @return the expectedResult
215         */
216        public List<Boolean> getExpectedResult() {
217                return Collections.unmodifiableList(expectedResult);
218        }
219
220        /**
221         * Used by the framework.
222         * 
223         * @return the havingGroup
224         */
225        public List<List<Integer>> getHavingGroup() {
226                return Collections.unmodifiableList(havingGroup);
227        }
228
229        /**
230         * Used by the framework.
231         * 
232         * @return the expectedGroup
233         */
234        public List<List<Matcher<String>>> getExpectedGroup() {
235                return Collections.unmodifiableList(expectedGroup);
236        }
237
238}