Skip to content

Commit e13b4ec

Browse files
committed
Fixed tests related to begin and end SQL block
1 parent 83efa0f commit e13b4ec

File tree

3 files changed

+108
-34
lines changed

3 files changed

+108
-34
lines changed
Lines changed: 48 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
11
package info.codesaway.bex.matching;
22

33
import static info.codesaway.bex.BEXPairs.bexPair;
4+
import static info.codesaway.bex.BEXSide.LEFT;
5+
import static info.codesaway.bex.BEXSide.RIGHT;
46
import static info.codesaway.bex.matching.BEXMatchingUtilities.currentChar;
5-
import static info.codesaway.bex.matching.BEXMatchingUtilities.hasCaseInsensitiveText;
67
import static info.codesaway.bex.matching.BEXMatchingUtilities.hasText;
78
import static info.codesaway.bex.matching.BEXMatchingUtilities.isWordCharacter;
9+
import static info.codesaway.bex.matching.BEXMatchingUtilities.previousChar;
10+
import static java.util.stream.Collectors.toList;
811

912
import java.util.Arrays;
1013
import java.util.Collections;
1114
import java.util.List;
1215
import java.util.Optional;
1316
import java.util.Set;
17+
import java.util.function.BiPredicate;
1418
import java.util.function.Function;
1519

1620
import info.codesaway.bex.BEXPair;
21+
import info.codesaway.bex.BEXSide;
1722
import info.codesaway.bex.ImmutableIntRangeMap;
1823

1924
public enum BEXMatchingLanguage implements MatchingLanguage {
@@ -24,30 +29,37 @@ public enum BEXMatchingLanguage implements MatchingLanguage {
2429
* SQL Matching language
2530
* @since 0.11
2631
*/
27-
SQL(BEXMatchingUtilities::parseSQLTextStates, true, bexPair("BEGIN", "END")),
32+
SQL(BEXMatchingUtilities::parseSQLTextStates, "@", true, bexPair("BEGIN", "END")),
2833

2934
// End of enum
3035
;
3136

3237
private final Function<CharSequence, ImmutableIntRangeMap<MatchingStateOption>> parseFunction;
38+
private final String specialWordCharacters;
3339
private final boolean hasCaseInsensitiveDelimiters;
34-
private final List<BEXPair<String>> delimiters;
40+
private final List<Optional<BEXPair<String>>> delimiters;
3541

3642
private BEXMatchingLanguage(
3743
final Function<CharSequence, ImmutableIntRangeMap<MatchingStateOption>> parseFunction) {
3844
this.parseFunction = parseFunction;
45+
this.specialWordCharacters = "";
3946
this.hasCaseInsensitiveDelimiters = false;
4047
this.delimiters = Collections.emptyList();
4148
}
4249

4350
@SafeVarargs
4451
private BEXMatchingLanguage(
4552
final Function<CharSequence, ImmutableIntRangeMap<MatchingStateOption>> parseFunction,
53+
final String specialWordCharacters,
4654
final boolean hasCaseInsensitiveDelimiters,
4755
final BEXPair<String>... delimiters) {
4856
this.parseFunction = parseFunction;
57+
this.specialWordCharacters = specialWordCharacters;
4958
this.hasCaseInsensitiveDelimiters = hasCaseInsensitiveDelimiters;
50-
this.delimiters = Arrays.asList(delimiters);
59+
this.delimiters = Arrays.stream(delimiters)
60+
// Wrap in Optional, so don't have to create new Optional objects for each matching
61+
.map(Optional::of)
62+
.collect(toList());
5163
}
5264

5365
@Override
@@ -59,19 +71,10 @@ public ImmutableIntRangeMap<MatchingStateOption> parse(final CharSequence text)
5971
public Optional<BEXPair<String>> findStartDelimiter(final CharSequence text, final int index,
6072
final Set<MatchingLanguageSetting> settings) {
6173

62-
for (BEXPair<String> delimiter : this.delimiters) {
63-
String s = delimiter.getLeft();
74+
Optional<BEXPair<String>> delimiter = this.findDelimiter(LEFT, text, index);
6475

65-
if (this.hasCaseInsensitiveDelimiters) {
66-
if (hasCaseInsensitiveText(text, index, s)
67-
&& !isWordCharacter(currentChar(text, index + s.length()))) {
68-
return Optional.of(delimiter);
69-
}
70-
} else {
71-
if (hasText(text, index, s) && !isWordCharacter(currentChar(text, index + s.length()))) {
72-
return Optional.of(delimiter);
73-
}
74-
}
76+
if (delimiter.isPresent()) {
77+
return delimiter;
7578
}
7679

7780
return MatchingLanguage.super.findStartDelimiter(text, index, settings);
@@ -82,30 +85,41 @@ public MatchingDelimiterState findEndDelimiter(final BEXPair<String> lastDelimit
8285
final int index,
8386
final Set<MatchingLanguageSetting> settings) {
8487

85-
for (BEXPair<String> delimiter : this.delimiters) {
86-
String s = delimiter.getRight();
88+
Optional<BEXPair<String>> delimiter = this.findDelimiter(RIGHT, text, index);
8789

88-
if (this.hasCaseInsensitiveDelimiters) {
89-
if (hasCaseInsensitiveText(text, index, s)
90-
&& !isWordCharacter(currentChar(text, index + s.length()))) {
91-
MatchingDelimiterResult result = lastDelimiter != null
92-
&& s.equalsIgnoreCase(lastDelimiter.getRight())
93-
? MatchingDelimiterResult.FOUND
94-
: MatchingDelimiterResult.MISMATCHED;
90+
if (delimiter.isPresent()) {
91+
String s = delimiter.get().getRight();
9592

96-
return new MatchingDelimiterState(result, s);
97-
}
98-
} else {
99-
if (hasText(text, index, s) && !isWordCharacter(currentChar(text, index + s.length()))) {
100-
MatchingDelimiterResult result = lastDelimiter != null && s.equals(lastDelimiter.getRight())
101-
? MatchingDelimiterResult.FOUND
102-
: MatchingDelimiterResult.MISMATCHED;
93+
BiPredicate<String, String> equals = this.hasCaseInsensitiveDelimiters
94+
? String::equalsIgnoreCase
95+
: String::equals;
96+
97+
MatchingDelimiterResult result = lastDelimiter != null && equals.test(s, lastDelimiter.getRight())
98+
? MatchingDelimiterResult.FOUND
99+
: MatchingDelimiterResult.MISMATCHED;
100+
101+
return new MatchingDelimiterState(result, s);
102+
}
103103

104-
return new MatchingDelimiterState(result, s);
104+
return MatchingLanguage.super.findEndDelimiter(lastDelimiter, text, index, settings);
105+
}
106+
107+
private Optional<BEXPair<String>> findDelimiter(final BEXSide side, final CharSequence text, final int index) {
108+
if (!this.delimiters.isEmpty() && !this.isPartOfWord(previousChar(text, index))) {
109+
for (Optional<BEXPair<String>> delimiter : this.delimiters) {
110+
String s = delimiter.get().get(side);
111+
char nextChar = currentChar(text, index + s.length());
112+
113+
if (hasText(text, index, s, this.hasCaseInsensitiveDelimiters) && !this.isPartOfWord(nextChar)) {
114+
return delimiter;
105115
}
106116
}
107117
}
108118

109-
return MatchingLanguage.super.findEndDelimiter(lastDelimiter, text, index, settings);
119+
return Optional.empty();
120+
}
121+
122+
private boolean isPartOfWord(final char c) {
123+
return isWordCharacter(c) || this.specialWordCharacters.indexOf(c) != -1;
110124
}
111125
}

BEXCodeCompare/src/main/java/info/codesaway/bex/matching/BEXMatchingUtilities.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,22 @@ public static boolean isWordCharacter(final char c) {
9797
return Character.isAlphabetic(c) || Character.isDigit(c) || c == '_';
9898
}
9999

100+
/**
101+
*
102+
* @param text
103+
* @param startIndex
104+
* @param search
105+
* @param isCaseInsensitive
106+
* @return
107+
* @since 0.11
108+
*/
109+
public static boolean hasText(final CharSequence text, final int startIndex, final String search,
110+
final boolean isCaseInsensitive) {
111+
return isCaseInsensitive
112+
? hasCaseInsensitiveText(text, startIndex, search)
113+
: hasText(text, startIndex, search);
114+
}
115+
100116
public static boolean hasText(final CharSequence text, final int startIndex, final String search) {
101117
int index = startIndex;
102118

@@ -114,6 +130,14 @@ public static boolean hasText(final CharSequence text, final int startIndex, fin
114130
return true;
115131
}
116132

133+
/**
134+
*
135+
* @param text
136+
* @param startIndex
137+
* @param search
138+
* @return
139+
* @since 0.11
140+
*/
117141
public static boolean hasCaseInsensitiveText(final CharSequence text, final int startIndex, final String search) {
118142
int index = startIndex;
119143

BEXCodeCompare/src/test/java/info/codesaway/bex/matching/BEXParseSQLTest.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,47 @@ void testTrailingBeginDoesNotMatch() {
132132
testNoBEXMatch(pattern, text, BEXMatchingLanguage.SQL);
133133
}
134134

135+
@Test
136+
void testVariableNamedBeginMatches() {
137+
String pattern = ":[value]";
138+
String text = "@BEGIN";
139+
140+
BEXMatcher bexMatcher = testJustBEXMatch(pattern, text, BEXMatchingLanguage.SQL);
141+
assertThat(bexMatcher.group("value")).isEqualTo("@BEGIN");
142+
}
143+
144+
@Test
145+
void testVariableNamedContainingBeginMatches() {
146+
String pattern = ":[value]";
147+
String text = "@lets_begin";
148+
149+
BEXMatcher bexMatcher = testJustBEXMatch(pattern, text, BEXMatchingLanguage.SQL);
150+
assertThat(bexMatcher.group("value")).isEqualTo("@lets_begin");
151+
}
152+
135153
@Test
136154
void testTrailingEndDoesNotMatch() {
137155
String pattern = ":[stuff]";
138156
String text = "END";
139157

140158
testNoBEXMatch(pattern, text, BEXMatchingLanguage.SQL);
141159
}
160+
161+
@Test
162+
void testVariableNamedEndMatches() {
163+
String pattern = ":[value]";
164+
String text = "@end";
165+
166+
BEXMatcher bexMatcher = testJustBEXMatch(pattern, text, BEXMatchingLanguage.SQL);
167+
assertThat(bexMatcher.group("value")).isEqualTo("@end");
168+
}
169+
170+
@Test
171+
void testVariableNamedContainingEndMatches() {
172+
String pattern = ":[value]";
173+
String text = "@the_end";
174+
175+
BEXMatcher bexMatcher = testJustBEXMatch(pattern, text, BEXMatchingLanguage.SQL);
176+
assertThat(bexMatcher.group("value")).isEqualTo("@the_end");
177+
}
142178
}

0 commit comments

Comments
 (0)