diff --git a/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/CodeTemplateManager.java b/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/CodeTemplateManager.java index 0932e814..f2d36a3b 100755 --- a/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/CodeTemplateManager.java +++ b/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/CodeTemplateManager.java @@ -18,11 +18,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; +import java.util.*; import javax.swing.text.BadLocationException; import javax.swing.text.Document; @@ -104,8 +100,7 @@ public synchronized CodeTemplate getTemplate(RSyntaxTextArea textArea) { int index = Collections.binarySearch(templates, s, comparator); return index>=0 ? templates.get(index) : null; } catch (BadLocationException ble) { - ble.printStackTrace(); - throw new InternalError("Error in CodeTemplateManager"); + throw new InternalError("Error in CodeTemplateManager", ble); } } @@ -219,9 +214,6 @@ public synchronized void replaceTemplates(CodeTemplate[] newTemplates) { */ public synchronized boolean saveTemplates() { - if (templates==null) { - return true; - } if (directory==null || !directory.isDirectory()) { return false; } @@ -292,10 +284,13 @@ public synchronized int setTemplateDirectory(File dir) { } temp.add((CodeTemplate)obj); d.close(); - } catch (/*IO, NoSuchElement*/Exception e) { + } catch (IOException | ArrayIndexOutOfBoundsException | NoSuchElementException e) { // NoSuchElementException can be thrown when reading // an XML file not in the format expected by XMLDecoder. // (e.g. CodeTemplates in an old format). + // ArrayIndexOutOfBoundsException is thrown by XMLDecoder + // in certain circumstances for XML that isn't an encoded + // Java object. e.printStackTrace(); } } diff --git a/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/ParserManager.java b/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/ParserManager.java index 43cc6244..30116ca0 100755 --- a/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/ParserManager.java +++ b/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/ParserManager.java @@ -42,7 +42,6 @@ import org.fife.ui.rtextarea.RTextAreaHighlighter.HighlightInfo; - /** * Manages running a parser object for an RSyntaxTextArea. * @@ -84,7 +83,7 @@ class ParserManager implements DocumentListener, ActionListener, /** * Whether to print debug messages while running parsers. */ - private static final boolean DEBUG_PARSING; + private boolean debugParsing; /** * The default delay between the last key press and when the document @@ -113,6 +112,7 @@ class ParserManager implements DocumentListener, ActionListener, * parsing. */ ParserManager(int delay, RSyntaxTextArea textArea) { + debugParsing = getDefaultDebugParsing(); this.textArea = textArea; textArea.getDocument().addDocumentListener(this); textArea.addPropertyChangeListener("document", this); @@ -138,7 +138,7 @@ public void actionPerformed(ActionEvent e) { } long begin = 0; - if (DEBUG_PARSING) { + if (debugParsing) { begin = System.currentTimeMillis(); } @@ -150,7 +150,7 @@ public void actionPerformed(ActionEvent e) { int lastLine = lastOffsetModded==null ? root.getElementCount()-1 : root.getElementIndex(lastOffsetModded.getOffset()); firstOffsetModded = lastOffsetModded = null; - if (DEBUG_PARSING) { + if (debugParsing) { System.out.println("[DEBUG]: Minimum lines to parse: " + firstLine + "-" + lastLine); } @@ -172,7 +172,7 @@ public void actionPerformed(ActionEvent e) { doc.readUnlock(); } - if (DEBUG_PARSING) { + if (debugParsing) { float time = (System.currentTimeMillis()-begin)/1000f; System.out.println("Total parsing time: " + time + " seconds"); } @@ -220,7 +220,7 @@ private void addParserNoticeHighlights(ParseResult res) { return; } - if (DEBUG_PARSING) { + if (debugParsing) { System.out.println("[DEBUG]: Adding parser notices from " + res.getParser()); } @@ -238,7 +238,7 @@ private void addParserNoticeHighlights(ParseResult res) { textArea.getHighlighter(); for (ParserNotice notice : notices) { - if (DEBUG_PARSING) { + if (debugParsing) { System.out.println("[DEBUG]: ... adding: " + notice); } try { @@ -255,7 +255,7 @@ private void addParserNoticeHighlights(ParseResult res) { } - if (DEBUG_PARSING) { + if (debugParsing) { System.out.println("[DEBUG]: Done adding parser notices from " + res.getParser()); } @@ -348,6 +348,18 @@ public void forceReparsing(int parser) { } + private static boolean getDefaultDebugParsing() { + boolean debugParsing; + try { + debugParsing = Boolean.getBoolean(PROPERTY_DEBUG_PARSING); + } catch (AccessControlException ace) { + // Likely an applet's security manager. + debugParsing = false; // FindBugs + } + return debugParsing; + } + + /** * Returns the delay between the last "concurrent" edit and when the * document is reparsed. @@ -664,7 +676,7 @@ private void removeParserNotices(ParseResult res) { i.remove(); removed = true; } - if (DEBUG_PARSING) { + if (debugParsing) { String text = removed ? "[DEBUG]: ... notice removed: " : "[DEBUG]: ... notice not removed: "; System.out.println(text + pair.notice); @@ -716,6 +728,18 @@ public void restartParsing() { } + /** + * Toggles whether debug information about parsing is + * written to stdout. + * + * @param debugParsing Whether debug parsing information + * is enabled. + */ + public void setDebugParsing(boolean debugParsing) { + this.debugParsing = debugParsing; + } + + /** * Sets the delay between the last "concurrent" edit and when the document * is reparsed. @@ -747,7 +771,7 @@ public void setDelay(int millis) { private boolean shouldRemoveNotice(ParserNotice notice, ParseResult res) { - if (DEBUG_PARSING) { + if (debugParsing) { System.out.println("[DEBUG]: ... ... shouldRemoveNotice " + notice + ": " + (notice.getParser()==res.getParser())); } @@ -791,16 +815,4 @@ private static class NoticeHighlightPair { } - static { - boolean debugParsing; - try { - debugParsing = Boolean.getBoolean(PROPERTY_DEBUG_PARSING); - } catch (AccessControlException ace) { - // Likely an applet's security manager. - debugParsing = false; // FindBugs - } - DEBUG_PARSING = debugParsing; - } - - } diff --git a/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKit.java b/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKit.java index 85957318..c1e038de 100755 --- a/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKit.java +++ b/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKit.java @@ -12,6 +12,7 @@ import java.awt.Font; import java.awt.Point; import java.awt.event.ActionEvent; +import java.text.BreakIterator; import java.text.CharacterIterator; import java.util.ResourceBundle; import java.util.Stack; @@ -1048,7 +1049,7 @@ protected int getPreviousWord(RTextArea textArea, int offs) } else { // offs == start => previous word is on previous line if (line == 0) { - return -1; + return BreakIterator.DONE; } elem = root.getElement(--line); offs = elem.getEndOffset() - 1; @@ -1169,6 +1170,25 @@ private static boolean isIdentifierChar(char ch) { } + /** + * Moves the caret to the end of the document, taking into account code + * folding. + */ + public static class EndAction extends RTextAreaEditorKit.EndAction { + + public EndAction(String name, boolean select) { + super(name, select); + } + + @Override + protected int getVisibleEnd(RTextArea textArea) { + RSyntaxTextArea rsta = (RSyntaxTextArea)textArea; + return rsta.getLastVisibleOffset(); + } + + } + + /** * Positions the caret at the end of the word. This class is here to * better handle finding the "end of the word" in programming languages. @@ -1322,24 +1342,6 @@ protected Fold getClosestFold(RSyntaxTextArea textArea) { public static class GoToMatchingBracketAction extends RecordableTextAction { - /** - * Moves the caret to the end of the document, taking into account code - * folding. - */ - public static class EndAction extends RTextAreaEditorKit.EndAction { - - public EndAction(String name, boolean select) { - super(name, select); - } - - @Override - protected int getVisibleEnd(RTextArea textArea) { - RSyntaxTextArea rsta = (RSyntaxTextArea)textArea; - return rsta.getLastVisibleOffset(); - } - - } - private static final long serialVersionUID = 1L; private Point bracketInfo; @@ -1956,7 +1958,7 @@ protected int getNextWord(RTextArea textArea, int offs) Element root = doc.getDefaultRootElement(); int line = root.getElementIndex(offs); int end = root.getElement(line).getEndOffset() - 1; - if (offs==end) {// If we're already at the end of the line... + if (offs==end) { // If we're already at the end of the line... RSyntaxTextArea rsta = (RSyntaxTextArea)textArea; if (rsta.isCodeFoldingEnabled()) { // Start of next visible line FoldManager fm = rsta.getFoldManager(); @@ -2033,34 +2035,28 @@ public void actionPerformedImpl(ActionEvent e, RTextArea textArea) { if (RSyntaxTextArea.getTemplatesEnabled()) { - Document doc = textArea.getDocument(); - if (doc != null) { - - try { - - CodeTemplateManager manager = RSyntaxTextArea. - getCodeTemplateManager(); - CodeTemplate template = manager==null ? null : - manager.getTemplate(rsta); - - // A non-null template means modify the text to insert! - if (template!=null) { - template.invoke(rsta); - } + try { - // No template - insert default text. This is - // exactly what DefaultKeyTypedAction does. - else { - doDefaultInsert(rsta); - } + CodeTemplateManager manager = RSyntaxTextArea. + getCodeTemplateManager(); + CodeTemplate template = manager==null ? null : + manager.getTemplate(rsta); - } catch (BadLocationException ble) { - UIManager.getLookAndFeel(). - provideErrorFeedback(textArea); + // A non-null template means modify the text to insert! + if (template!=null) { + template.invoke(rsta); } + // No template - insert default text. This is + // exactly what DefaultKeyTypedAction does. + else { + doDefaultInsert(rsta); + } - } // End of if (doc!=null). + } catch (BadLocationException ble) { + UIManager.getLookAndFeel(). + provideErrorFeedback(textArea); + } } // End of if (textArea.getTemplatesEnabled()). diff --git a/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/SyntaxScheme.java b/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/SyntaxScheme.java index 5995567c..8af5f2c0 100755 --- a/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/SyntaxScheme.java +++ b/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/SyntaxScheme.java @@ -105,7 +105,7 @@ void changeBaseFont(Font oldFont, Font newFont) { for (Style style : styles) { if (style != null && style.font != null) { if (style.font.getFamily().equals(oldFont.getFamily()) && - style.font.getSize() == oldFont.getSize()) { + style.font.getSize2D() == oldFont.getSize2D()) { int styleFontStyle = style.font.getStyle(); // Keep bold or italic style.font = newFont.deriveFont(styleFontStyle); } diff --git a/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/focusabletip/FocusableTip.java b/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/focusabletip/FocusableTip.java index 7f357404..49ee6f60 100755 --- a/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/focusabletip/FocusableTip.java +++ b/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/focusabletip/FocusableTip.java @@ -374,7 +374,7 @@ public void keyPressed(KeyEvent e) { } else if (e.getKeyCode()==KeyEvent.VK_F2) { if (tipWindow!=null && !tipWindow.getFocusableWindowState()) { - tipWindow.actionPerformed(null); + tipWindow.actionPerformed(); e.consume(); // Don't do bookmarking stuff } } diff --git a/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/focusabletip/TipWindow.java b/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/focusabletip/TipWindow.java index 740cf470..cd2f2b36 100755 --- a/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/focusabletip/TipWindow.java +++ b/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/focusabletip/TipWindow.java @@ -17,8 +17,6 @@ import java.awt.Point; import java.awt.Rectangle; import java.awt.Window; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; @@ -54,7 +52,7 @@ * @author Robert Futrell * @version 1.0 */ -class TipWindow extends JWindow implements ActionListener { +class TipWindow extends JWindow { private FocusableTip ft; private JEditorPane textArea; @@ -130,9 +128,7 @@ public void keyPressed(KeyEvent e) { } - @Override - public void actionPerformed(ActionEvent e) { - + public void actionPerformed() { if (!getFocusableWindowState()) { setFocusableWindowState(true); setBottomPanel(); @@ -145,11 +141,8 @@ public void windowLostFocus(WindowEvent e) { } }); ft.removeListeners(); - if (e==null) { // Didn't get here via our mouseover timer - requestFocus(); - } + requestFocus(); } - } @@ -252,6 +245,11 @@ private static Border getReplacementForFlatLafBorder(Border border) { } + protected String getText() { + return textArea.getText(); + } + + private static Border getToolTipBorder() { Border border = TipUtil.getToolTipBorder(); @@ -375,7 +373,7 @@ private TipListener() { @Override public void mousePressed(MouseEvent e) { - actionPerformed(null); // Manually create "real" window + actionPerformed(); // Manually create "real" window } @Override diff --git a/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/modes/PerlTokenMaker.flex b/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/modes/PerlTokenMaker.flex index 18c50e94..0640dce3 100755 --- a/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/modes/PerlTokenMaker.flex +++ b/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/modes/PerlTokenMaker.flex @@ -179,7 +179,7 @@ import org.fife.ui.rsyntaxtextarea.*; this.offsetShift = -text.offset + startOffset; // Start off in the proper state. - int state = Token.NULL; + int state; switch (initialTokenType) { case Token.LITERAL_STRING_DOUBLE_QUOTE: state = STRING; @@ -214,7 +214,7 @@ import org.fife.ui.rsyntaxtextarea.*; start = text.offset; break; default: - state = Token.NULL; + state = YYINITIAL; } s = text; @@ -692,11 +692,11 @@ ErrorIdentifier = ({NonSeparator}+) { [^\n\\\$\@\%\"]+ {} - \n { addToken(start,zzStartRead-1, Token.LITERAL_STRING_DOUBLE_QUOTE); return firstToken; } \\.? { /* Skip escaped chars. */ } {Variable} { int temp=zzStartRead; addToken(start,zzStartRead-1, Token.LITERAL_STRING_DOUBLE_QUOTE); addToken(temp,zzMarkedPos-1, Token.VARIABLE); start = zzMarkedPos; } {VariableStart} {} \" { yybegin(YYINITIAL); addToken(start,zzStartRead, Token.LITERAL_STRING_DOUBLE_QUOTE); } + \n | <> { addToken(start,zzStartRead-1, Token.LITERAL_STRING_DOUBLE_QUOTE); return firstToken; } } @@ -704,19 +704,19 @@ ErrorIdentifier = ({NonSeparator}+) { [^\n\\\']+ {} \\.? { /* Skip escaped single quotes only, but this should still work. */ } - \n { addToken(start,zzStartRead-1, Token.LITERAL_CHAR); return firstToken; } \' { yybegin(YYINITIAL); addToken(start,zzStartRead, Token.LITERAL_CHAR); } + \n | <> { addToken(start,zzStartRead-1, Token.LITERAL_CHAR); return firstToken; } } { [^\n\\\$\@\%\`]+ {} - \n { addToken(start,zzStartRead-1, Token.LITERAL_BACKQUOTE); return firstToken; } \\.? { /* Skip escaped chars. */ } {Variable} { int temp=zzStartRead; addToken(start,zzStartRead-1, Token.LITERAL_BACKQUOTE); addToken(temp,zzMarkedPos-1, Token.VARIABLE); start = zzMarkedPos; } {VariableStart} {} \` { yybegin(YYINITIAL); addToken(start,zzStartRead, Token.LITERAL_BACKQUOTE); } + \n | <> { addToken(start,zzStartRead-1, Token.LITERAL_BACKQUOTE); return firstToken; } } @@ -733,10 +733,10 @@ ErrorIdentifier = ({NonSeparator}+) /* syntactic rules. */ "EOF" { if (start==zzStartRead) { addToken(Token.PREPROCESSOR); addNullToken(); return firstToken; } } [^\n\\\$\@\%]+ {} - \n { addToken(start,zzStartRead-1, Token.PREPROCESSOR); addEndToken(INTERNAL_HEREDOC_EOF_UNQUOTED); return firstToken; } \\.? { /* Skip escaped chars. */ } {Variable} { int temp=zzStartRead; addToken(start,zzStartRead-1, Token.PREPROCESSOR); addToken(temp,zzMarkedPos-1, Token.VARIABLE); start = zzMarkedPos; } {VariableStart} {} + \n | <> { addToken(start,zzStartRead-1, Token.PREPROCESSOR); addEndToken(INTERNAL_HEREDOC_EOF_UNQUOTED); return firstToken; } } @@ -750,8 +750,8 @@ ErrorIdentifier = ({NonSeparator}+) /* EOF and any other chars. */ "EOF" { if (start==zzStartRead) { addToken(Token.PREPROCESSOR); addNullToken(); return firstToken; } } [^\n\\]+ {} - \n { addToken(start,zzStartRead-1, Token.PREPROCESSOR); addEndToken(INTERNAL_HEREDOC_EOF_SINGLE_QUOTED); return firstToken; } \\.? { /* Skip escaped chars. */ } + \n | <> { addToken(start,zzStartRead-1, Token.PREPROCESSOR); addEndToken(INTERNAL_HEREDOC_EOF_SINGLE_QUOTED); return firstToken; } } @@ -768,10 +768,10 @@ ErrorIdentifier = ({NonSeparator}+) /* syntactic rules. */ "EOT" { if (start==zzStartRead) { addToken(Token.PREPROCESSOR); addNullToken(); return firstToken; } } [^\n\\\$\@\%]+ {} - \n { addToken(start,zzStartRead-1, Token.PREPROCESSOR); addEndToken(INTERNAL_HEREDOC_EOT_UNQUOTED); return firstToken; } \\.? { /* Skip escaped chars. */ } {Variable} { int temp=zzStartRead; addToken(start,zzStartRead-1, Token.PREPROCESSOR); addToken(temp,zzMarkedPos-1, Token.VARIABLE); start = zzMarkedPos; } {VariableStart} {} + \n | <> { addToken(start,zzStartRead-1, Token.PREPROCESSOR); addEndToken(INTERNAL_HEREDOC_EOT_UNQUOTED); return firstToken; } } diff --git a/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/modes/PerlTokenMaker.java b/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/modes/PerlTokenMaker.java index c0b5bff7..4deab5b4 100755 --- a/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/modes/PerlTokenMaker.java +++ b/RSyntaxTextArea/src/main/java/org/fife/ui/rsyntaxtextarea/modes/PerlTokenMaker.java @@ -1503,7 +1503,7 @@ public Token getTokenList(Segment text, int initialTokenType, int startOffset) { this.offsetShift = -text.offset + startOffset; // Start off in the proper state. - int state = Token.NULL; + int state; switch (initialTokenType) { case Token.LITERAL_STRING_DOUBLE_QUOTE: state = STRING; @@ -1538,7 +1538,7 @@ public Token getTokenList(Segment text, int initialTokenType, int startOffset) { start = text.offset; break; default: - state = Token.NULL; + state = YYINITIAL; } s = text; @@ -1874,117 +1874,117 @@ else if (zzAtEOF) { { addToken(Token.FUNCTION); } case 52: break; - case 36: - { boolean highlightedAsRegex = false; - if (firstToken==null) { - addToken(Token.REGEX); - highlightedAsRegex = true; - } - else { - // If this is *likely* to be a regex, based on - // the previous token, highlight it as such. - Token t = firstToken.getLastNonCommentNonWhitespaceToken(); - if (regexCanFollow(t)) { - addToken(Token.REGEX); - highlightedAsRegex = true; - } - } - // If it doesn't *appear* to be a regex, highlight it as - // individual tokens. - if (!highlightedAsRegex) { - int temp = zzStartRead + 1; - addToken(zzStartRead, zzStartRead, Token.OPERATOR); - zzStartRead = zzCurrentPos = zzMarkedPos = temp; - } - } - case 53: break; case 30: { addToken(Token.VARIABLE); } - case 54: break; + case 53: break; case 1: { addToken(Token.ERROR_IDENTIFIER); } - case 55: break; + case 54: break; case 24: { addToken(start,zzStartRead-1, Token.PREPROCESSOR); addEndToken(INTERNAL_HEREDOC_EOT_SINGLE_QUOTED); return firstToken; } - case 56: break; + case 55: break; case 4: { addToken(Token.COMMENT_EOL); addNullToken(); return firstToken; } - case 57: break; + case 56: break; case 29: { addToken(Token.PREPROCESSOR); addNullToken(); return firstToken; } - case 58: break; + case 57: break; case 41: { if (start==zzStartRead) { int temp=zzStartRead; addToken(start,zzStartRead-1, Token.COMMENT_DOCUMENTATION); addToken(temp,zzMarkedPos-1, Token.COMMENT_EOL); start = zzMarkedPos; } } - case 59: break; + case 58: break; case 44: { start = zzStartRead; yybegin(HEREDOC_EOF_SINGLE_QUOTED); } - case 60: break; + case 59: break; case 45: { start = zzStartRead; yybegin(HEREDOC_EOT_SINGLE_QUOTED); } - case 61: break; + case 60: break; case 42: { start = zzStartRead; yybegin(HEREDOC_EOF_UNQUOTED); } - case 62: break; + case 61: break; case 13: { /* Skip escaped chars. */ } - case 63: break; + case 62: break; case 37: { addToken(Token.REGEX); } - case 64: break; + case 63: break; case 18: { yybegin(YYINITIAL); addToken(start,zzStartRead, Token.LITERAL_CHAR); } - case 65: break; + case 64: break; case 28: { addToken(Token.LITERAL_NUMBER_HEXADECIMAL); } - case 66: break; + case 65: break; case 21: { addToken(start,zzStartRead-1, Token.PREPROCESSOR); addEndToken(INTERNAL_HEREDOC_EOF_UNQUOTED); return firstToken; } - case 67: break; + case 66: break; case 6: { addToken(Token.WHITESPACE); } - case 68: break; + case 67: break; case 10: { start = zzMarkedPos-1; yybegin(CHAR_LITERAL); } - case 69: break; + case 68: break; case 3: { addToken(Token.LITERAL_NUMBER_DECIMAL_INT); } - case 70: break; + case 69: break; case 33: { int temp=zzStartRead; addToken(start,zzStartRead-1, Token.LITERAL_STRING_DOUBLE_QUOTE); addToken(temp,zzMarkedPos-1, Token.VARIABLE); start = zzMarkedPos; } - case 71: break; + case 70: break; case 20: { yybegin(YYINITIAL); addToken(start,zzStartRead, Token.LITERAL_BACKQUOTE); } - case 72: break; + case 71: break; case 15: { yybegin(YYINITIAL); addToken(start,zzStartRead, Token.LITERAL_STRING_DOUBLE_QUOTE); } - case 73: break; + case 72: break; case 16: { /* Skip escaped single quotes only, but this should still work. */ } - case 74: break; + case 73: break; case 23: { addToken(start,zzStartRead-1, Token.PREPROCESSOR); addEndToken(INTERNAL_HEREDOC_EOT_UNQUOTED); return firstToken; } + case 74: break; + case 36: + { boolean highlightedAsRegex = false; + if (firstToken==null) { + addToken(Token.REGEX); + highlightedAsRegex = true; + } + else { + // If this is *likely* to be a regex, based on + // the previous token, highlight it as such. + Token t = firstToken.getLastNonCommentNonWhitespaceToken(); + if (regexCanFollow(t)) { + addToken(Token.REGEX); + highlightedAsRegex = true; + } + } + // If it doesn't *appear* to be a regex, highlight it as + // individual tokens. + if (!highlightedAsRegex) { + int temp = zzStartRead + 1; + addToken(zzStartRead, zzStartRead, Token.OPERATOR); + zzStartRead = zzCurrentPos = zzMarkedPos = temp; + } + } case 75: break; case 35: { int temp=zzStartRead; addToken(start,zzStartRead-1, Token.PREPROCESSOR); addToken(temp,zzMarkedPos-1, Token.VARIABLE); start = zzMarkedPos; diff --git a/RSyntaxTextArea/src/test/java/org/fife/TestUtil.java b/RSyntaxTextArea/src/test/java/org/fife/TestUtil.java new file mode 100644 index 00000000..1741bcef --- /dev/null +++ b/RSyntaxTextArea/src/test/java/org/fife/TestUtil.java @@ -0,0 +1,86 @@ +/** + * This library is distributed under a modified BSD license. See the included + * LICENSE file for details. + */ +package org.fife; + +import org.fife.io.UnicodeWriter; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; + + +/** + * Utility methods for unit tests. + */ +public final class TestUtil { + + private static String DEFAULT_TEMP_FILE_EXTENSION = ".tmp"; + + + /** + * Private constructor to prevent instantiation. + */ + private TestUtil() { + // Do nothing + } + + + /** + * Creates a temporary file with extension {@code ".tmp"}. + * + * @param content The content of the file. + * @return The file. + * @throws IOException If an IO error occurs. + * @see #createFile(String, String) + * @see #createFile(String, String, File) + */ + public static File createFile(String content) throws IOException { + return createFile(DEFAULT_TEMP_FILE_EXTENSION, content); + } + + + /** + * Creates a temporary file. + * + * @param fileExtension The extension for the file. + * @param content The content of the file. + * @return The file. + * @throws IOException If an IO error occurs. + * @see #createFile(String) + * @see #createFile(String, String, File) + */ + public static File createFile(String fileExtension, String content) throws IOException { + File file = File.createTempFile("unitTest", fileExtension); + file.deleteOnExit(); + UnicodeWriter uw = new UnicodeWriter(file, "UTF-8"); + try (PrintWriter w = new PrintWriter(uw)) { + w.println(content); + } + return file; + } + + + /** + * Creates a temporary file. + * + * @param fileExtension The extension for the file. + * @param content The content of the file. + * @param directory The parent directory for the file. + * @return The file. + * @throws IOException If an IO error occurs. + * @see #createFile(String) + * @see #createFile(String, String) + */ + public static File createFile(String fileExtension, String content, File directory) + throws IOException { + File file = File.createTempFile("unitTest", fileExtension, directory); + file.deleteOnExit(); + UnicodeWriter uw = new UnicodeWriter(file, "UTF-8"); + try (PrintWriter w = new PrintWriter(uw)) { + w.println(content); + } + return file; + } +} diff --git a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/CodeTemplateManagerTest.java b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/CodeTemplateManagerTest.java index a83e26a8..08ff72a6 100644 --- a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/CodeTemplateManagerTest.java +++ b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/CodeTemplateManagerTest.java @@ -4,7 +4,7 @@ */ package org.fife.ui.rsyntaxtextarea; - +import org.fife.TestUtil; import org.fife.ui.rsyntaxtextarea.templates.CodeTemplate; import org.fife.ui.rsyntaxtextarea.templates.StaticCodeTemplate; import org.junit.jupiter.api.Assertions; @@ -101,6 +101,7 @@ void testRemoveTemplate_codeTemplateArg_happyPath_found() { CodeTemplateManager manager = new CodeTemplateManager(); CodeTemplate template = new StaticCodeTemplate("id", "foo", "bar"); manager.addTemplate(template); + Assertions.assertEquals(1, manager.getTemplates().length); Assertions.assertTrue(manager.removeTemplate(template)); Assertions.assertEquals(0, manager.getTemplates().length); } @@ -129,6 +130,41 @@ void testReplaceTemplates() { } + @Test + void testSaveTemplates_nullDirectory() { + CodeTemplateManager manager = new CodeTemplateManager(); + Assertions.assertFalse(manager.saveTemplates()); + } + + + @Test + void testSaveTemplates_directoryDoesNotExist() throws IOException { + CodeTemplateManager manager = new CodeTemplateManager(); + // Because we ensure the directory exists when setting it, this + // can only happen if the directory is removed out form under us. + Path tempDir = Files.createTempDirectory("testDir"); + manager.setTemplateDirectory(tempDir.toFile()); + Files.delete(tempDir); + Assertions.assertFalse(manager.saveTemplates()); + } + + + @Test + void testSaveTemplates_deletesOldFiles() throws IOException { + + CodeTemplateManager manager = new CodeTemplateManager(); + + File tempDir = Files.createTempDirectory("testDir").toFile(); + manager.setTemplateDirectory(tempDir); + + File oldFile = TestUtil.createFile( + ".xml", "", tempDir); + + manager.saveTemplates(); + Assertions.assertEquals(0, tempDir.listFiles().length); + } + + @Test void testSetTemplateDirectory_dirExists() throws IOException { @@ -147,6 +183,17 @@ void testSetTemplateDirectory_dirExists() throws IOException { } + @Test + void testSetTemplateDirectory_dirExists_xmlFileThatIsNotACodeTemplate() throws IOException { + + CodeTemplateManager manager = new CodeTemplateManager(); + File file = TestUtil.createFile(".xml", ""); + + // The non-template XML file is ignored. + Assertions.assertEquals(0, manager.setTemplateDirectory(file.getParentFile())); + } + + @Test void testSetTemplateDirectory_dirDoesNotExist() { diff --git a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/ErrorStripTest.java b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/ErrorStripTest.java index 91343f05..a2ad7a79 100644 --- a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/ErrorStripTest.java +++ b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/ErrorStripTest.java @@ -9,6 +9,7 @@ import org.fife.ui.rtextarea.SmartHighlightPainter; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -63,18 +64,44 @@ void testDoLayout() { } @Test - void testGetSetCaretMarkerColor() { + void testGetSetCaretMarkerColor_darkForeground() { Assertions.assertEquals(Color.BLACK, strip.getCaretMarkerColor()); strip.setCaretMarkerColor(Color.RED); Assertions.assertEquals(Color.RED, strip.getCaretMarkerColor()); } + @Test + void testGetSetCaretMarkerColor_nullDoesNothing() { + Assertions.assertEquals(Color.BLACK, strip.getCaretMarkerColor()); + strip.setCaretMarkerColor(null); + Assertions.assertEquals(Color.BLACK, strip.getCaretMarkerColor()); + } + + @Test + @Disabled("Can't set up LookAndFeel where this will have light FG early enough") + void testGetSetCaretMarkerColor_lightForeground() { + strip.setForeground(Color.WHITE); + Assertions.assertEquals(createTextArea().getCaretColor(), strip.getCaretMarkerColor()); + strip.setCaretMarkerColor(Color.RED); + Assertions.assertEquals(Color.RED, strip.getCaretMarkerColor()); + } + + @Test + void testGetSetCaretMarkerOnTop() { + Assertions.assertFalse(strip.isCaretMarkerOnTop()); + strip.setCaretMarkerOnTop(true); + Assertions.assertTrue(strip.isCaretMarkerOnTop()); + } + @Test void testGetSetFollowCaret() { Assertions.assertTrue(strip.getFollowCaret()); strip.setFollowCaret(false); Assertions.assertFalse(strip.getFollowCaret()); + // Repeating the same value does nothing + strip.setFollowCaret(false); + Assertions.assertFalse(strip.getFollowCaret()); } @@ -91,6 +118,9 @@ void testGetSetShowMarkAll() { Assertions.assertTrue(strip.getShowMarkAll()); strip.setShowMarkAll(false); Assertions.assertFalse(strip.getShowMarkAll()); + // Calling again with the same value does nothing + strip.setShowMarkAll(false); + Assertions.assertFalse(strip.getShowMarkAll()); } @@ -99,6 +129,9 @@ void testGetSetShowMarkedOccurrences() { Assertions.assertTrue(strip.getShowMarkedOccurrences()); strip.setShowMarkedOccurrences(false); Assertions.assertFalse(strip.getShowMarkedOccurrences()); + // Calling again with the same values does nothing + strip.setShowMarkedOccurrences(false); + Assertions.assertFalse(strip.getShowMarkedOccurrences()); } @@ -125,7 +158,17 @@ void testGetToolTipText_invalidMouseEvent() { @Test void testPaint() { + strip.addNotify(); + strip.setSize(strip.getPreferredSize()); + strip.doLayout(); + Graphics g = createTestGraphics(); + strip.paint(g); + } + + @Test + void testPaint_paintCaretMarkerOnTop() { + strip.setCaretMarkerOnTop(true); strip.addNotify(); strip.setSize(strip.getPreferredSize()); strip.doLayout(); @@ -160,7 +203,11 @@ public ParseResult parse(RSyntaxDocument doc, String style) { // Note some notices on the same line result.addNotice(new DefaultParserNotice(this, "test notice", 1)); result.addNotice(new DefaultParserNotice(this, "second notice", 1)); - result.addNotice(new DefaultParserNotice(this, "third notice", 2)); + DefaultParserNotice thirdNotice = + new DefaultParserNotice(this, "third notice", 2); + thirdNotice.setColor(null); + result.addNotice(thirdNotice); + return result; } } diff --git a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/ParserManagerTest.java b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/ParserManagerTest.java index 18d29e68..9a14e8be 100644 --- a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/ParserManagerTest.java +++ b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/ParserManagerTest.java @@ -7,11 +7,10 @@ import org.fife.ui.SwingRunnerExtension; import org.fife.ui.rsyntaxtextarea.parser.*; import org.fife.ui.rtextarea.RTextScrollPane; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import java.awt.event.ActionEvent; import java.awt.event.MouseEvent; @@ -27,43 +26,34 @@ @ExtendWith(SwingRunnerExtension.class) class ParserManagerTest extends AbstractRSyntaxTextAreaTest { - private boolean origDebugParsing; - - @BeforeEach - void setUp() { - origDebugParsing = Boolean.getBoolean(ParserManager.PROPERTY_DEBUG_PARSING); - System.setProperty(ParserManager.PROPERTY_DEBUG_PARSING, "true"); - } - - - @AfterEach - void tearDown() { - System.setProperty(ParserManager.PROPERTY_DEBUG_PARSING, Boolean.toString(origDebugParsing)); - } - - - @Test - void testConstructor_oneArg() { + @ParameterizedTest + @ValueSource(strings = { "true", "false" }) + void testConstructor_oneArg(String debugParsing) { RSyntaxTextArea textArea = createTextArea(); ParserManager manager = new ParserManager(textArea); + manager.setDebugParsing(Boolean.parseBoolean(debugParsing)); Assertions.assertEquals(1250, manager.getDelay()); } - @Test - void testConstructor_twoArg() { + @ParameterizedTest + @ValueSource(strings = { "true", "false" }) + void testConstructor_twoArg(String debugParsing) { RSyntaxTextArea textArea = createTextArea(); ParserManager manager = new ParserManager(2000, textArea); + manager.setDebugParsing(Boolean.parseBoolean(debugParsing)); Assertions.assertEquals(2000, manager.getDelay()); } - @Test - void testActionPerformed_noParsers() { + @ParameterizedTest + @ValueSource(strings = { "true", "false" }) + void testActionPerformed_noParsers(String debugParsing) { RSyntaxTextArea textArea = createTextArea(); ParserManager manager = new ParserManager(textArea); + manager.setDebugParsing(Boolean.parseBoolean(debugParsing)); Assertions.assertEquals(0, manager.getParserNotices().size()); manager.actionPerformed(new ActionEvent(textArea, 0, null)); @@ -71,8 +61,9 @@ void testActionPerformed_noParsers() { } - @Test - void testActionPerformed_parsersFireChangeEvents() { + @ParameterizedTest + @ValueSource(strings = { "true", "false" }) + void testActionPerformed_parsersFireChangeEvents(String debugParsing) { AbstractParser parser = new AbstractParser() { @Override @@ -86,6 +77,7 @@ public ParseResult parse(RSyntaxDocument doc, String style) { RSyntaxTextArea textArea = createTextArea(); ParserManager manager = new ParserManager(textArea); + manager.setDebugParsing(Boolean.parseBoolean(debugParsing)); manager.addParser(parser); Assertions.assertEquals(0, manager.getParserNotices().size()); @@ -95,11 +87,13 @@ public ParseResult parse(RSyntaxDocument doc, String style) { } - @Test - void testAddRemoveParser() { + @ParameterizedTest + @ValueSource(strings = { "true", "false" }) + void testAddRemoveParser(String debugParsing) { RSyntaxTextArea textArea = createTextArea(); ParserManager manager = new ParserManager(textArea); + manager.setDebugParsing(Boolean.parseBoolean(debugParsing)); Assertions.assertEquals(0, manager.getParserCount()); @@ -118,8 +112,9 @@ public ParseResult parse(RSyntaxDocument doc, String style) { } - @Test - void testClearParsers() { + @ParameterizedTest + @ValueSource(strings = { "true", "false" }) + void testClearParsers(String debugParsing) { AbstractParser parser = new AbstractParser() { @Override @@ -133,6 +128,7 @@ public ParseResult parse(RSyntaxDocument doc, String style) { RSyntaxTextArea textArea = createTextArea(); ParserManager manager = new ParserManager(textArea); + manager.setDebugParsing(Boolean.parseBoolean(debugParsing)); manager.addParser(parser); Assertions.assertEquals(1, manager.getParserCount()); @@ -146,8 +142,9 @@ public ParseResult parse(RSyntaxDocument doc, String style) { } - @Test - void testForceReparsing_parsersFireChangeEvents() { + @ParameterizedTest + @ValueSource(strings = { "true", "false" }) + void testForceReparsing_parsersFireChangeEvents(String debugParsing) { boolean[] parserNoticeChangeEventFired = { false }; @@ -167,14 +164,66 @@ public ParseResult parse(RSyntaxDocument doc, String style) { PropertyChangeListener listener = evt -> parserNoticeChangeEventFired[0] = true; textArea.addPropertyChangeListener(RSyntaxTextArea.PARSER_NOTICES_PROPERTY, listener); - textArea.forceReparsing(parser); + Assertions.assertTrue(textArea.forceReparsing(parser)); Assertions.assertTrue(parserNoticeChangeEventFired[0]); } - @Test - void testGetToolTipText() { + @ParameterizedTest + @ValueSource(strings = { "true", "false" }) + void testForceReparsing_disabledParserClearsItsNotices(String debugParsing) { + + AbstractParser parser = new AbstractParser() { + @Override + public ParseResult parse(RSyntaxDocument doc, String style) { + DefaultParseResult result = new DefaultParseResult(this); + result.addNotice(new DefaultParserNotice(this, "test", 1)); + return result; + } + }; + + RSyntaxTextArea textArea = createTextArea(); + // Remove the fold parser so our test parser is the only one + textArea.setCodeFoldingEnabled(false); + textArea.addParser(parser); + + // Initial run - adds notices to the text area. + Assertions.assertTrue(textArea.forceReparsing(parser)); + Assertions.assertFalse(textArea.getParserNotices().isEmpty()); + + // After being disabled and rerun - clears notices from the text area. + parser.setEnabled(false); + Assertions.assertTrue(textArea.forceReparsing(parser)); + Assertions.assertTrue(textArea.getParserNotices().isEmpty()); + + } + + + @ParameterizedTest + @ValueSource(strings = { "true", "false" }) + void testGetSetDelay(String debugParsing) { + + RSyntaxTextArea textArea = createTextArea(); + ParserManager manager = new ParserManager(textArea); + manager.setDebugParsing(Boolean.parseBoolean(debugParsing)); + + manager.setDelay(12345); + Assertions.assertEquals(12345, manager.getDelay()); + + manager.restartParsing(); + try { + manager.setDelay(54321); + Assertions.assertEquals(54321, manager.getDelay()); + } finally { + manager.stopParsing(); + } + } + + + @ParameterizedTest + @ValueSource(strings = { "true", "false" }) + void testGetToolTipText(String debugParsing) { AbstractParser parser = new AbstractParser() { @Override @@ -190,6 +239,7 @@ public ParseResult parse(RSyntaxDocument doc, String style) { textArea.setAntiAliasingEnabled(false); // Needed to initialize font metrics cache RTextScrollPane sp = new RTextScrollPane(textArea); // text area needs a parent ParserManager manager = new ParserManager(textArea); + manager.setDebugParsing(Boolean.parseBoolean(debugParsing)); manager.addParser(parser); manager.forceReparsing(0); @@ -200,12 +250,25 @@ public ParseResult parse(RSyntaxDocument doc, String style) { } - @Test - void testPropertyChange_document() { + @ParameterizedTest + @ValueSource(strings = { "true", "false" }) + void testInsertUpdate(String debugParsing) { RSyntaxTextArea textArea = createTextArea(); ParserManager manager = new ParserManager(textArea); + manager.setDebugParsing(Boolean.parseBoolean(debugParsing)); + + textArea.insert("inserted text", 5); + } + + @ParameterizedTest + @ValueSource(strings = { "true", "false" }) + void testPropertyChange_document(String debugParsing) { + + RSyntaxTextArea textArea = createTextArea(); + ParserManager manager = new ParserManager(textArea); + manager.setDebugParsing(Boolean.parseBoolean(debugParsing)); RSyntaxDocument origDocument = (RSyntaxDocument)textArea.getDocument(); RSyntaxDocument newDocument = new RSyntaxDocument(SyntaxConstants.SYNTAX_STYLE_C); @@ -215,4 +278,16 @@ void testPropertyChange_document() { // listener removed (along with all others) Assertions.assertEquals(0, origDocument.getDocumentListeners().length); } + + + @ParameterizedTest + @ValueSource(strings = { "true", "false" }) + void testRemoveUpdate(String debugParsing) { + + RSyntaxTextArea textArea = createTextArea(); + ParserManager manager = new ParserManager(textArea); + manager.setDebugParsing(Boolean.parseBoolean(debugParsing)); + + textArea.replaceRange("", 5, 9); + } } diff --git a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitBeginWordActionTest.java b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitBeginWordActionTest.java new file mode 100644 index 00000000..6da883ab --- /dev/null +++ b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitBeginWordActionTest.java @@ -0,0 +1,136 @@ +/* + * This library is distributed under a modified BSD license. See the included + * LICENSE file for details. + */ +package org.fife.ui.rsyntaxtextarea; + +import org.fife.ui.SwingRunnerExtension; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + + +/** + * Unit tests for this action. + * + * @author Robert Futrell + * @version 1.0 + */ +@ExtendWith(SwingRunnerExtension.class) +class RSyntaxTextAreaEditorKitBeginWordActionTest extends AbstractRSyntaxTextAreaTest { + + + @Test + void testActionPerformedImpl_inWhitespace_middleOfWhitespace() { + + String text = "word word"; + RSyntaxTextArea textArea = new RSyntaxTextArea(text); + textArea.setCaretPosition(7); + + RSyntaxTextAreaEditorKit.BeginWordAction action = + new RSyntaxTextAreaEditorKit.BeginWordAction("name", false); + + // Moves to the beginning of whitespace between words + action.actionPerformedImpl(null, textArea); + Assertions.assertEquals(4, textArea.getSelectionStart()); + Assertions.assertEquals(4, textArea.getSelectionEnd()); + } + + + @Test + void testActionPerformedImpl_inWhitespace_endOfWhitespace() { + + String text = "word word"; + RSyntaxTextArea textArea = new RSyntaxTextArea(text); + textArea.setCaretPosition(text.lastIndexOf(' ')); + + RSyntaxTextAreaEditorKit.BeginWordAction action = + new RSyntaxTextAreaEditorKit.BeginWordAction("name", false); + + // Moves to the beginning of whitespace between words + action.actionPerformedImpl(null, textArea); + Assertions.assertEquals(4, textArea.getSelectionStart()); + Assertions.assertEquals(4, textArea.getSelectionEnd()); + } + + + @Test + void testActionPerformedImpl_inWord_beginningOfWord() { + + String text = "word word word"; + RSyntaxTextArea textArea = new RSyntaxTextArea(text); + textArea.setCaretPosition(5); + + RSyntaxTextAreaEditorKit.BeginWordAction action = + new RSyntaxTextAreaEditorKit.BeginWordAction("name", false); + + action.actionPerformedImpl(null, textArea); + Assertions.assertEquals(5, textArea.getSelectionStart()); + Assertions.assertEquals(5, textArea.getSelectionEnd()); + } + + + @Test + void testActionPerformedImpl_inWord_endOfWord() { + + String text = "word word word"; + RSyntaxTextArea textArea = new RSyntaxTextArea(text); + textArea.setCaretPosition(8); + + RSyntaxTextAreaEditorKit.BeginWordAction action = + new RSyntaxTextAreaEditorKit.BeginWordAction("name", false); + + action.actionPerformedImpl(null, textArea); + Assertions.assertEquals(5, textArea.getSelectionStart()); + Assertions.assertEquals(5, textArea.getSelectionEnd()); + } + + + @Test + void testActionPerformedImpl_inWord_middleOfWord() { + + String text = "word word word"; + RSyntaxTextArea textArea = new RSyntaxTextArea(text); + textArea.setCaretPosition(7); + + RSyntaxTextAreaEditorKit.BeginWordAction action = + new RSyntaxTextAreaEditorKit.BeginWordAction("name", false); + + action.actionPerformedImpl(null, textArea); + Assertions.assertEquals(5, textArea.getSelectionStart()); + Assertions.assertEquals(5, textArea.getSelectionEnd()); + } + + + @Test + void testActionPerformedImpl_offset0() { + + String text = "word word word"; + RSyntaxTextArea textArea = new RSyntaxTextArea(text); + textArea.setCaretPosition(0); + + RSyntaxTextAreaEditorKit.BeginWordAction action = + new RSyntaxTextAreaEditorKit.BeginWordAction("name", false); + + action.actionPerformedImpl(null, textArea); + Assertions.assertEquals(0, textArea.getSelectionStart()); + Assertions.assertEquals(0, textArea.getSelectionEnd()); + } + + + @Test + void testActionPerformedImpl_startOfLineOtherThanTheFirst() { + + String text = "line 1\nline 2"; + RSyntaxTextArea textArea = new RSyntaxTextArea(text); + int secondLineStartOffs = text.indexOf('\n') + 1; + textArea.setCaretPosition(secondLineStartOffs); + + RSyntaxTextAreaEditorKit.BeginWordAction action = + new RSyntaxTextAreaEditorKit.BeginWordAction("name", false); + + action.actionPerformedImpl(null, textArea); + Assertions.assertEquals(secondLineStartOffs, textArea.getSelectionStart()); + Assertions.assertEquals(secondLineStartOffs, textArea.getSelectionEnd()); + } +} diff --git a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitChangeFoldStateActionTest.java b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitChangeFoldStateActionTest.java new file mode 100644 index 00000000..388bd294 --- /dev/null +++ b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitChangeFoldStateActionTest.java @@ -0,0 +1,65 @@ +/* + * This library is distributed under a modified BSD license. See the included + * LICENSE file for details. + */ +package org.fife.ui.rsyntaxtextarea; + +import org.fife.ui.SwingRunnerExtension; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import javax.swing.*; + + +/** + * Unit tests for this action. + * + * @author Robert Futrell + * @version 1.0 + */ +@ExtendWith(SwingRunnerExtension.class) +class RSyntaxTextAreaEditorKitChangeFoldStateActionTest extends AbstractRSyntaxTextAreaTest { + + + @Test + void testConstructor_4Arg() { + Action a = new RSyntaxTextAreaEditorKit.ChangeFoldStateAction( + "name", null, "desc", 1, null + ); + Assertions.assertEquals("name", a.getValue(Action.NAME)); + Assertions.assertNull(a.getValue(Action.LARGE_ICON_KEY)); + Assertions.assertNull(a.getValue(Action.SMALL_ICON)); + Assertions.assertEquals("desc", a.getValue(Action.SHORT_DESCRIPTION)); + Assertions.assertEquals(1, a.getValue(Action.MNEMONIC_KEY)); + Assertions.assertNull(a.getValue(Action.ACCELERATOR_KEY)); + } + + + @Test + void testActionPerformedImpl_codeFoldingNotEnabled() { + RSyntaxTextArea textArea = createTextArea(); + textArea.setCodeFoldingEnabled(false); + + RSyntaxTextAreaEditorKit.ChangeFoldStateAction a = + new RSyntaxTextAreaEditorKit.ChangeFoldStateAction("name", true); + + a.actionPerformedImpl(null, textArea); + // TODO: Mock and verify error feedback is triggered + } + + + @Test + void testActionPerformedImpl_codeFoldingEnabled_closesClosestFold() { + RSyntaxTextArea textArea = createTextArea(); + textArea.setCaretPosition(0); // On the first fold's line + + Assertions.assertFalse(textArea.getFoldManager().getFold(0).isCollapsed()); + + RSyntaxTextAreaEditorKit.ChangeFoldStateAction a = + new RSyntaxTextAreaEditorKit.ChangeFoldStateAction("name", true); + + a.actionPerformedImpl(null, textArea); + Assertions.assertTrue(textArea.getFoldManager().getFold(0).isCollapsed()); + } +} diff --git a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitCloseCurlyBraceActionTest.java b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitCloseCurlyBraceActionTest.java new file mode 100644 index 00000000..569ab1d8 --- /dev/null +++ b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitCloseCurlyBraceActionTest.java @@ -0,0 +1,125 @@ +/* + * This library is distributed under a modified BSD license. See the included + * LICENSE file for details. + */ +package org.fife.ui.rsyntaxtextarea; + +import org.fife.ui.SwingRunnerExtension; +import org.fife.ui.rtextarea.RecordableTextAction; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + + +/** + * Unit tests for this action. + * + * @author Robert Futrell + * @version 1.0 + */ +@ExtendWith(SwingRunnerExtension.class) +class RSyntaxTextAreaEditorKitCloseCurlyBraceActionTest extends AbstractRSyntaxTextAreaTest { + + + @Test + void testActionPerformedImpl_enabledAndEditable_alignCurlyBraces_emptyDocument() { + + RSyntaxTextArea textArea = createTextArea(""); + + RecordableTextAction a = new RSyntaxTextAreaEditorKit.CloseCurlyBraceAction(); + a.actionPerformedImpl(null, textArea); + + String expected = "}"; + Assertions.assertEquals(expected, textArea.getText()); + } + + + @Test + void testActionPerformedImpl_enabledAndEditable_alignCurlyBraces_newCloseCurly() { + + RSyntaxTextArea textArea = createTextArea("{\n printf(\"hi\");\n "); + textArea.setCaretPosition(textArea.getDocument().getLength()); + + RecordableTextAction a = new RSyntaxTextAreaEditorKit.CloseCurlyBraceAction(); + a.actionPerformedImpl(null, textArea); + + // Verify the last line's whitespace is removed + String expected = "{\n printf(\"hi\");\n}"; + Assertions.assertEquals(expected, textArea.getText()); + } + + + @Test + void testActionPerformedImpl_enabledAndEditable_alignCurlyBraces_newCloseCurly_languageWithoutCurlies() { + + RSyntaxTextArea textArea = createTextArea(SyntaxConstants.SYNTAX_STYLE_CSV, "{\n hi\n "); + textArea.setCaretPosition(textArea.getDocument().getLength()); + + RecordableTextAction a = new RSyntaxTextAreaEditorKit.CloseCurlyBraceAction(); + a.actionPerformedImpl(null, textArea); + + // Verify the closing curly is simply inserted since it's not semantically meaningful + String expected = "{\n hi\n }"; + Assertions.assertEquals(expected, textArea.getText()); + } + + + @Test + void testActionPerformedImpl_enabledAndEditable_alignCurlyBraces_newCloseCurly_nonWhitespace() { + + RSyntaxTextArea textArea = createTextArea("{\n printf(\"hi\");\n xxx "); + textArea.setCaretPosition(textArea.getDocument().getLength()); + + RecordableTextAction a = new RSyntaxTextAreaEditorKit.CloseCurlyBraceAction(); + a.actionPerformedImpl(null, textArea); + + // Verify the last line's whitespace isn't removed due to "xxx" + String expected = "{\n printf(\"hi\");\n xxx }"; + Assertions.assertEquals(expected, textArea.getText()); + } + + + @Test + void testActionPerformedImpl_enabledAndEditable_alignCurlyBracesFalse_newCloseCurly() { + + RSyntaxTextArea textArea = createTextArea("{\n printf(\"hi\");\n "); + textArea.setCaretPosition(textArea.getDocument().getLength()); + textArea.setAutoIndentEnabled(false); + + RecordableTextAction a = new RSyntaxTextAreaEditorKit.CloseCurlyBraceAction(); + a.actionPerformedImpl(null, textArea); + + // Verify the last line's whitespace isn't removed + String expected = "{\n printf(\"hi\");\n }"; + Assertions.assertEquals(expected, textArea.getText()); + } + + + @Test + void testActionPerformedImpl_notEditable() { + RSyntaxTextArea textArea = createTextArea(); + textArea.setEditable(false); + String origText = textArea.getText(); + RecordableTextAction a = new RSyntaxTextAreaEditorKit.CloseCurlyBraceAction(); + a.actionPerformedImpl(null, textArea); + Assertions.assertEquals(origText, textArea.getText()); + } + + + @Test + void testActionPerformedImpl_notEnabled() { + RSyntaxTextArea textArea = createTextArea(); + textArea.setEnabled(false); + String origText = textArea.getText(); + RecordableTextAction a = new RSyntaxTextAreaEditorKit.CloseCurlyBraceAction(); + a.actionPerformedImpl(null, textArea); + Assertions.assertEquals(origText, textArea.getText()); + } + + + @Test + void getGetMacroId() { + RecordableTextAction a = new RSyntaxTextAreaEditorKit.CloseCurlyBraceAction(); + Assertions.assertEquals(RSyntaxTextAreaEditorKit.rstaCloseCurlyBraceAction, a.getMacroID()); + } +} diff --git a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitCloseMarkupTagActionTest.java b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitCloseMarkupTagActionTest.java new file mode 100644 index 00000000..36a6c4cb --- /dev/null +++ b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitCloseMarkupTagActionTest.java @@ -0,0 +1,237 @@ +/* + * This library is distributed under a modified BSD license. See the included + * LICENSE file for details. + */ +package org.fife.ui.rsyntaxtextarea; + +import org.fife.ui.SwingRunnerExtension; +import org.fife.ui.rsyntaxtextarea.modes.XMLTokenMaker; +import org.fife.ui.rtextarea.RecordableTextAction; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + + +/** + * Unit tests for this action. + * + * @author Robert Futrell + * @version 1.0 + */ +@ExtendWith(SwingRunnerExtension.class) +class RSyntaxTextAreaEditorKitCloseMarkupTagActionTest extends AbstractRSyntaxTextAreaTest { + + private boolean xmlDefaultClosingTags; + + @BeforeEach + void setUp() { + xmlDefaultClosingTags = XMLTokenMaker.getCompleteCloseMarkupTags(); + } + + + @AfterEach + void tearDown() { + XMLTokenMaker.setCompleteCloseTags(xmlDefaultClosingTags); + } + + + @Test + void testActionPerformedImpl_markup_typingClosingTag() { + + RSyntaxTextArea textArea = createTextArea(SyntaxConstants.SYNTAX_STYLE_XML, + "<"); + textArea.setCaretPosition(textArea.getDocument().getLength()); + + RecordableTextAction a = new RSyntaxTextAreaEditorKit.CloseMarkupTagAction(); + a.actionPerformedImpl(null, textArea); + + String expected = ""; + Assertions.assertEquals(expected, textArea.getText()); + Assertions.assertEquals(textArea.getDocument().getLength(), textArea.getCaretPosition()); + } + + + @Test + void testActionPerformedImpl_markup_typingClosingTag_nested() { + + RSyntaxTextArea textArea = createTextArea(SyntaxConstants.SYNTAX_STYLE_XML, + "<"); + textArea.setCaretPosition(textArea.getDocument().getLength()); + + RecordableTextAction a = new RSyntaxTextAreaEditorKit.CloseMarkupTagAction(); + a.actionPerformedImpl(null, textArea); + + String expected = ""; + Assertions.assertEquals(expected, textArea.getText()); + Assertions.assertEquals(textArea.getDocument().getLength(), textArea.getCaretPosition()); + } + + + @Test + void testActionPerformedImpl_markup_typingClosingTag_attributesAreSkipped() { + + RSyntaxTextArea textArea = createTextArea(SyntaxConstants.SYNTAX_STYLE_XML, + "<"); + textArea.setCaretPosition(textArea.getDocument().getLength()); + + RecordableTextAction a = new RSyntaxTextAreaEditorKit.CloseMarkupTagAction(); + a.actionPerformedImpl(null, textArea); + + String expected = ""; + Assertions.assertEquals(expected, textArea.getText()); + Assertions.assertEquals(textArea.getDocument().getLength(), textArea.getCaretPosition()); + } + + + @Test + void testActionPerformedImpl_markup_typingClosingTag_spaceBeforeTagName() { + + RSyntaxTextArea textArea = createTextArea(SyntaxConstants.SYNTAX_STYLE_XML, + "< foo><"); + textArea.setCaretPosition(textArea.getDocument().getLength()); + + RecordableTextAction a = new RSyntaxTextAreaEditorKit.CloseMarkupTagAction(); + a.actionPerformedImpl(null, textArea); + + String expected = "< foo>"; + Assertions.assertEquals(expected, textArea.getText()); + Assertions.assertEquals(textArea.getDocument().getLength(), textArea.getCaretPosition()); + } + + + @Test + void testActionPerformedImpl_markup_typingClosingTag_butDisabledForLanguage() { + + XMLTokenMaker.setCompleteCloseTags(false); + RSyntaxTextArea textArea = createTextArea(SyntaxConstants.SYNTAX_STYLE_XML, + "<"); + textArea.setCaretPosition(textArea.getDocument().getLength()); + + RecordableTextAction a = new RSyntaxTextAreaEditorKit.CloseMarkupTagAction(); + a.actionPerformedImpl(null, textArea); + + String expected = "<"); + textArea.setCaretPosition(textArea.getDocument().getLength()); + textArea.setCloseMarkupTags(false); + + RecordableTextAction a = new RSyntaxTextAreaEditorKit.CloseMarkupTagAction(); + a.actionPerformedImpl(null, textArea); + + String expected = " after the first "{" + Assertions.assertEquals(1, textArea.getCaretPosition()); + Assertions.assertNull(textArea.getSelectedText()); + } + + + @Test + void testActionPerformedImpl_folding_selectTrue() { + + String text = "{\n printf(\"Hi\");\n {\n printf(\"Bye\");\n }\n}"; + RSyntaxTextArea textArea = createTextArea(SyntaxConstants.SYNTAX_STYLE_C, text); + textArea.setCaretPosition(0); + textArea.getFoldManager().getFold(0).setCollapsed(true); + + ActionEvent e = new ActionEvent(textArea, 0, "command"); + new RSyntaxTextAreaEditorKit.EndAction("foo", true).actionPerformedImpl(e, textArea); + + // Caret is at the end of the first line (last visible offset => after the first "{" + Assertions.assertEquals(1, textArea.getCaretPosition()); + Assertions.assertEquals("{", textArea.getSelectedText()); + } + + + @Test + void testActionPerformedImpl_noFolding_selectFalse() { + + String text = "line 1\nline 2\nline 3"; + RSyntaxTextArea textArea = createTextArea(SyntaxConstants.SYNTAX_STYLE_NONE, text); + + ActionEvent e = new ActionEvent(textArea, 0, "command"); + new RSyntaxTextAreaEditorKit.EndAction("foo", false).actionPerformedImpl(e, textArea); + + Assertions.assertEquals(text.length(), textArea.getCaretPosition()); + Assertions.assertNull(textArea.getSelectedText()); + } + + + @Test + void testActionPerformedImpl_noFolding_selectTrue() { + + String text = "line 1\nline 2\nline 3"; + RSyntaxTextArea textArea = createTextArea(SyntaxConstants.SYNTAX_STYLE_NONE, text); + textArea.setCaretPosition(0); + + ActionEvent e = new ActionEvent(textArea, 0, "command"); + new RSyntaxTextAreaEditorKit.EndAction("foo", true).actionPerformedImpl(e, textArea); + + Assertions.assertEquals(text.length(), textArea.getCaretPosition()); + Assertions.assertNotNull(textArea.getSelectedText()); + } + + + @Test + void testGetMacroID() { + Assertions.assertEquals("foo", + new RSyntaxTextAreaEditorKit.EndAction("foo", false).getMacroID()); + } +} diff --git a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitEndWordActionTest.java b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitEndWordActionTest.java index 463e60b8..2a908d0a 100755 --- a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitEndWordActionTest.java +++ b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitEndWordActionTest.java @@ -66,4 +66,37 @@ void testGetWordEnd_noSelection_happyPath() { } + @Test + void testGetWordEnd_noSelection_atNonWordChar() { + EndWordAction action = new EndWordAction("endWordAction", false); + String TEXT = "!@#$%^&*()"; + RSyntaxTextArea textArea = createTextArea(TEXT); + textArea.setCaretPosition(TEXT.indexOf('#')); + action.actionPerformed(createActionEvent(textArea)); + Assertions.assertEquals(TEXT.indexOf('#'), textArea.getCaretPosition()); + } + + + @Test + void testGetWordEnd_noSelection_endOfLine() { + EndWordAction action = new EndWordAction("endWordAction", false); + String TEXT = "111 111\n222 222"; + RSyntaxTextArea textArea = createTextArea(TEXT); + textArea.setCaretPosition(TEXT.indexOf('\n')); + action.actionPerformed(createActionEvent(textArea)); + Assertions.assertEquals("111 111".length(), textArea.getCaretPosition()); + } + + + @Test + void testGetWordEnd_noSelection_startOfLineOtherThanFirst() { + EndWordAction action = new EndWordAction("endWordAction", false); + String TEXT = "111 111\n222 222"; + RSyntaxTextArea textArea = createTextArea(TEXT); + textArea.setCaretPosition(TEXT.indexOf('\n') + 1); + action.actionPerformed(createActionEvent(textArea)); + Assertions.assertEquals("111 111\n222".length(), textArea.getCaretPosition()); + } + + } diff --git a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitExpandAllFoldsActionTest.java b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitExpandAllFoldsActionTest.java index cadd2d13..01feeb3d 100644 --- a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitExpandAllFoldsActionTest.java +++ b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitExpandAllFoldsActionTest.java @@ -13,6 +13,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import javax.swing.*; import java.awt.event.ActionEvent; @@ -25,6 +26,19 @@ @ExtendWith(SwingRunnerExtension.class) class RSyntaxTextAreaEditorKitExpandAllFoldsActionTest extends AbstractRSyntaxTextAreaTest { + @Test + void testConstructor_5Arg() { + Action a = new RSyntaxTextAreaEditorKit.ExpandAllFoldsAction( + "name", null, "desc", 1, null + ); + Assertions.assertEquals("name", a.getValue(Action.NAME)); + Assertions.assertNull(a.getValue(Action.LARGE_ICON_KEY)); + Assertions.assertNull(a.getValue(Action.SMALL_ICON)); + Assertions.assertEquals("desc", a.getValue(Action.SHORT_DESCRIPTION)); + Assertions.assertEquals(1, a.getValue(Action.MNEMONIC_KEY)); + Assertions.assertNull(a.getValue(Action.ACCELERATOR_KEY)); + } + @Test void testActionPerformedImpl_expandAllFolds() { @@ -58,6 +72,39 @@ void testActionPerformedImpl_expandAllFolds() { Assertions.assertFalse(foldManager.getFold(1).getChild(0).isCollapsed()); } + @Test + void testActionPerformedImpl_codeFoldingDisabled() { + + RSyntaxTextArea textArea = createTextArea(SyntaxConstants.SYNTAX_STYLE_JAVA, + "/*\n" + + "* comment\n" + + "*/\n" + + "public void foo() {\n" + + " /* comment\n" + + " two */\n" + + "}"); + + textArea.setCaretPosition(textArea.getDocument().getLength()); + + RecordableTextAction a = new RSyntaxTextAreaEditorKit.CollapseAllFoldsAction(); + ActionEvent e = createActionEvent(textArea, RSyntaxTextAreaEditorKit.rstaCollapseAllFoldsAction); + a.actionPerformedImpl(e, textArea); + + FoldManager foldManager = textArea.getFoldManager(); + Assertions.assertEquals(2, foldManager.getFoldCount()); + Assertions.assertTrue(foldManager.getFold(0).isCollapsed()); + Assertions.assertTrue(foldManager.getFold(1).isCollapsed()); + Assertions.assertTrue(foldManager.getFold(1).getChild(0).isCollapsed()); + + // Now disable code folding and expand all folds (irrelevant since folds should be destroyed) + textArea.setCodeFoldingEnabled(false); + a = new RSyntaxTextAreaEditorKit.ExpandAllFoldsAction(); + e = createActionEvent(textArea, RSyntaxTextAreaEditorKit.rstaExpandAllFoldsAction); + a.actionPerformedImpl(e, textArea); + + Assertions.assertEquals(0, foldManager.getFoldCount()); + } + @Test void testGetMacroId() { RSyntaxTextAreaEditorKit.ExpandAllFoldsAction a = new RSyntaxTextAreaEditorKit.ExpandAllFoldsAction(); diff --git a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitGoToMatchingBracketActionTest.java b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitGoToMatchingBracketActionTest.java index 405d4fd8..bd1f4a00 100644 --- a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitGoToMatchingBracketActionTest.java +++ b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitGoToMatchingBracketActionTest.java @@ -12,6 +12,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import javax.swing.*; import java.awt.event.ActionEvent; @@ -24,6 +25,19 @@ @ExtendWith(SwingRunnerExtension.class) class RSyntaxTextAreaEditorKitGoToMatchingBracketActionTest extends AbstractRSyntaxTextAreaTest { + @Test + void testConstructor_5Arg() { + Action a = new RSyntaxTextAreaEditorKit.GoToMatchingBracketAction( + "name", null, "desc", 1, null + ); + Assertions.assertEquals("name", a.getValue(Action.NAME)); + Assertions.assertNull(a.getValue(Action.LARGE_ICON_KEY)); + Assertions.assertNull(a.getValue(Action.SMALL_ICON)); + Assertions.assertEquals("desc", a.getValue(Action.SHORT_DESCRIPTION)); + Assertions.assertEquals(1, a.getValue(Action.MNEMONIC_KEY)); + Assertions.assertNull(a.getValue(Action.ACCELERATOR_KEY)); + } + @Test void testActionPerformedImpl_goToMatchingBracket() { @@ -44,6 +58,27 @@ void testActionPerformedImpl_goToMatchingBracket() { Assertions.assertEquals(expectedOffset, textArea.getCaretPosition()); } + @Test + void testActionPerformedImpl_noMatchingBracket() { + + // Missing the final closing bracket + String origContent = "public void foo() {\n" + + " if (something) {\n" + + " System.out.println(\"Hello world\");\n" + + " }"; + RSyntaxTextArea textArea = createTextArea(SyntaxConstants.SYNTAX_STYLE_JAVA, origContent); + + int firstCurlyOffs = origContent.indexOf('{'); + textArea.setCaretPosition(firstCurlyOffs); + + RecordableTextAction a = new RSyntaxTextAreaEditorKit.GoToMatchingBracketAction(); + ActionEvent e = createActionEvent(textArea, RSyntaxTextAreaEditorKit.rstaGoToMatchingBracketAction); + a.actionPerformedImpl(e, textArea); + + // Verify the caret hasn't moved + Assertions.assertEquals(firstCurlyOffs, textArea.getCaretPosition()); + } + @Test void testGetMacroId() { RSyntaxTextAreaEditorKit.GoToMatchingBracketAction a = new RSyntaxTextAreaEditorKit.GoToMatchingBracketAction(); diff --git a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitIncreaseFontSizeActionTest.java b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitIncreaseFontSizeActionTest.java index 2501eb6c..7ecb1fb3 100644 --- a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitIncreaseFontSizeActionTest.java +++ b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitIncreaseFontSizeActionTest.java @@ -11,6 +11,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import javax.swing.*; +import java.awt.*; import java.awt.event.ActionEvent; @@ -24,9 +26,23 @@ class RSyntaxTextAreaEditorKitIncreaseFontSizeActionTest extends AbstractRSyntaxTextAreaTest { @Test - void testActionPerformedImpl_increaseFontSize() { + void testConstructor_5Arg() { + Action a = new RSyntaxTextAreaEditorKit.IncreaseFontSizeAction( + "name", null, "desc", 1, null + ); + Assertions.assertEquals("name", a.getValue(Action.NAME)); + Assertions.assertNull(a.getValue(Action.LARGE_ICON_KEY)); + Assertions.assertNull(a.getValue(Action.SMALL_ICON)); + Assertions.assertEquals("desc", a.getValue(Action.SHORT_DESCRIPTION)); + Assertions.assertEquals(1, a.getValue(Action.MNEMONIC_KEY)); + Assertions.assertNull(a.getValue(Action.ACCELERATOR_KEY)); + } + + @Test + void testActionPerformedImpl_increaseFontSize_happyPath() { RSyntaxTextArea textArea = createTextArea(); + JScrollPane sp = new JScrollPane(textArea); int origFontSize = 0; for (Style style : textArea.getSyntaxScheme().getStyles()) { @@ -51,6 +67,55 @@ void testActionPerformedImpl_increaseFontSize() { Assertions.assertTrue(newFontSize > origFontSize); } + @Test + void testActionPerformedImpl_increaseFontSize_capsAtMaxSize() { + + // This action change the font size in increments of 1f, so we start + // with a font size close enough to the cap to hit it + float maxSize = 40f; + RSyntaxTextArea textArea = createTextArea(); + Font font = textArea.getFont(); + textArea.setFont(font.deriveFont(maxSize - 0.5f)); + float origFontSize = textArea.getFont().getSize2D(); + + RSyntaxTextAreaEditorKit.IncreaseFontSizeAction a = new RSyntaxTextAreaEditorKit.IncreaseFontSizeAction(); + ActionEvent e = createActionEvent(textArea, RSyntaxTextAreaEditorKit.rtaIncreaseFontSizeAction); + a.actionPerformedImpl(e, textArea); + + for (Style style : textArea.getSyntaxScheme().getStyles()) { + if (style.font != null) { + float newFontSize = style.font.getSize2D(); + Assertions.assertEquals(maxSize, newFontSize, 0.0001f); + } + } + Assertions.assertEquals(maxSize, textArea.getFont().getSize2D(), 0.0001f); + } + + @Test + void testActionPerformedImpl_increaseFontSize_alreadyLargerThanMaxSize() { + + // This action change the font size in increments of 1f, so we start + // with a font size close enough to the cap to hit it + float maxSize = 40f; + RSyntaxTextArea textArea = createTextArea(); + Font font = textArea.getFont(); + textArea.setFont(font.deriveFont(maxSize + 1f)); + float origFontSize = textArea.getFont().getSize2D(); + + RSyntaxTextAreaEditorKit.IncreaseFontSizeAction a = new RSyntaxTextAreaEditorKit.IncreaseFontSizeAction(); + ActionEvent e = createActionEvent(textArea, RSyntaxTextAreaEditorKit.rtaIncreaseFontSizeAction); + a.actionPerformedImpl(e, textArea); + + // Verify fonts remain unchanged in size + for (Style style : textArea.getSyntaxScheme().getStyles()) { + if (style.font != null) { + float newFontSize = style.font.getSize2D(); + Assertions.assertEquals(origFontSize, newFontSize, 0.0001f); + } + } + Assertions.assertEquals(origFontSize, textArea.getFont().getSize2D(), 0.0001f); + } + @Test void testGetMacroId() { RSyntaxTextAreaEditorKit.IncreaseFontSizeAction a = new RSyntaxTextAreaEditorKit.IncreaseFontSizeAction(); diff --git a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitInsertTabActionTest.java b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitInsertTabActionTest.java index e2588404..34a992d0 100644 --- a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitInsertTabActionTest.java +++ b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitInsertTabActionTest.java @@ -9,6 +9,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import javax.swing.*; import javax.swing.text.DefaultEditorKit; import java.awt.event.ActionEvent; @@ -23,6 +24,13 @@ class RSyntaxTextAreaEditorKitInsertTabActionTest extends AbstractRSyntaxTextAreaTest { + @Test + void testConstructor_nameArg() { + Action a = new RSyntaxTextAreaEditorKit.InsertTabAction("foo"); + Assertions.assertEquals("foo", a.getValue(Action.NAME)); + } + + @Test void testActionPerformedImpl_notEditable() { @@ -66,7 +74,28 @@ void testActionPerformedImpl_noSelection() { @Test - void testActionPerformedImpl_multiLineSelection() { + void testActionPerformedImpl_multiLineSelection_dotAtStartOfLine() { + + String origContent = "int main() {\n" + + "\tprintf(\"Hello world\n\");\n" + + "}"; + RSyntaxTextArea textArea = createTextArea(SyntaxConstants.SYNTAX_STYLE_C, origContent); + textArea.setCaretPosition(0); + textArea.moveCaretPosition(origContent.indexOf('\t')); + + ActionEvent e = new ActionEvent(textArea, 0, "command"); + new RSyntaxTextAreaEditorKit.InsertTabAction().actionPerformedImpl(e, textArea); + + // End line does not get indented since the caret was at the start of it + String expectedContent = "\tint main() {\n" + + "\tprintf(\"Hello world\n\");\n" + + "}"; + Assertions.assertEquals(expectedContent, textArea.getText()); + } + + + @Test + void testActionPerformedImpl_multiLineSelection_dotNotAtStartOfLine() { String origContent = "int main() {\n" + "\tprintf(\"Hello world\n\");\n" + @@ -78,6 +107,7 @@ void testActionPerformedImpl_multiLineSelection() { ActionEvent e = new ActionEvent(textArea, 0, "command"); new RSyntaxTextAreaEditorKit.InsertTabAction().actionPerformedImpl(e, textArea); + // End line gets indented since the caret was NOT at the start of it String expectedContent = "\tint main() {\n" + "\t\tprintf(\"Hello world\n\");\n" + "}"; diff --git a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitNextWordActionTest.java b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitNextWordActionTest.java index 7a454def..bf379a74 100644 --- a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitNextWordActionTest.java +++ b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitNextWordActionTest.java @@ -23,7 +23,126 @@ class RSyntaxTextAreaEditorKitNextWordActionTest extends AbstractRSyntaxTextArea @Test - void testActionPerformedImpl_noSelection() { + void testActionPerformedImpl_atEndOfDocument() { + + String text = "line 1\nline 2\nline 3"; + RSyntaxTextArea textArea = new RSyntaxTextArea(text); + textArea.setCaretPosition(text.length()); + + ActionEvent e = new ActionEvent(textArea, 0, "command"); + new RSyntaxTextAreaEditorKit.NextWordAction("foo", true).actionPerformedImpl(e, textArea); + + Assertions.assertEquals(text.length(), textArea.getCaretPosition()); + Assertions.assertNull(textArea.getSelectedText()); + } + + + @Test + void testActionPerformedImpl_atEndOfLine_codeFolding_noLaterVisibleLine_noSelection() { + + String text = "line 1 {\n foo;\n}"; + RSyntaxTextArea textArea = createTextArea(text); + textArea.setCaretPosition(text.indexOf('\n')); + textArea.setCodeFoldingEnabled(true); + textArea.getFoldManager().getFold(0).setCollapsed(true); + + ActionEvent e = new ActionEvent(textArea, 0, "command"); + new RSyntaxTextAreaEditorKit.NextWordAction("foo", false).actionPerformedImpl(e, textArea); + + // Because of the fold, we're already on the last visible offset + Assertions.assertEquals(text.indexOf('\n'), textArea.getCaretPosition()); + Assertions.assertNull(textArea.getSelectedText()); + } + + + @Test + void testActionPerformedImpl_atEndOfLine_codeFolding_noLaterVisibleLine_selection() { + + String text = "line 1 {\n foo;\n}"; + RSyntaxTextArea textArea = createTextArea(text); + textArea.setCaretPosition(text.indexOf('\n')); + textArea.setCodeFoldingEnabled(true); + textArea.getFoldManager().getFold(0).setCollapsed(true); + + ActionEvent e = new ActionEvent(textArea, 0, "command"); + new RSyntaxTextAreaEditorKit.NextWordAction("foo", true).actionPerformedImpl(e, textArea); + + // Because of the fold, we're already on the last visible offset + Assertions.assertEquals(text.indexOf('\n'), textArea.getCaretPosition()); + Assertions.assertNull(textArea.getSelectedText()); + } + + + @Test + void testActionPerformedImpl_atEndOfLine_codeFolding_laterVisibleLine_noSelection() { + + String text = "line 1 {\n foo;\n}\nlast line"; + RSyntaxTextArea textArea = createTextArea(text); + textArea.setCaretPosition(text.indexOf('\n')); + textArea.setCodeFoldingEnabled(true); + textArea.getFoldManager().getFold(0).setCollapsed(true); + + ActionEvent e = new ActionEvent(textArea, 0, "command"); + new RSyntaxTextAreaEditorKit.NextWordAction("foo", false).actionPerformedImpl(e, textArea); + + // Just go to the start of the next line + Assertions.assertEquals(text.indexOf("last line"), textArea.getCaretPosition()); + Assertions.assertNull(textArea.getSelectedText()); + } + + + @Test + void testActionPerformedImpl_atEndOfLine_codeFolding_laterVisibleLine_selection() { + + String text = "line 1 {\n foo;\n}\nlast line"; + RSyntaxTextArea textArea = createTextArea(text); + textArea.setCaretPosition(text.indexOf('\n')); + textArea.setCodeFoldingEnabled(true); + textArea.getFoldManager().getFold(0).setCollapsed(true); + + ActionEvent e = new ActionEvent(textArea, 0, "command"); + new RSyntaxTextAreaEditorKit.NextWordAction("foo", true).actionPerformedImpl(e, textArea); + + // Just go to the start of the next line + Assertions.assertEquals(text.indexOf("last line"), textArea.getCaretPosition()); + Assertions.assertEquals("\n foo;\n}\n", textArea.getSelectedText()); + } + + + @Test + void testActionPerformedImpl_atEndOfLine_noCodeFolding_noSelection() { + + String text = "line 1\nline 2\nline 3"; + RSyntaxTextArea textArea = new RSyntaxTextArea(text); + textArea.setCaretPosition(text.indexOf('\n')); + + ActionEvent e = new ActionEvent(textArea, 0, "command"); + new RSyntaxTextAreaEditorKit.NextWordAction("foo", false).actionPerformedImpl(e, textArea); + + // Just go to the start of the next line + Assertions.assertEquals(text.indexOf('\n') + 1, textArea.getCaretPosition()); + Assertions.assertNull(textArea.getSelectedText()); + } + + + @Test + void testActionPerformedImpl_atEndOfLine_noCodeFolding_selection() { + + String text = "line 1\nline 2\nline 3"; + RSyntaxTextArea textArea = new RSyntaxTextArea(text); + textArea.setCaretPosition(text.indexOf('\n')); + + ActionEvent e = new ActionEvent(textArea, 0, "command"); + new RSyntaxTextAreaEditorKit.NextWordAction("foo", true).actionPerformedImpl(e, textArea); + + // Just go to the start of the next line + Assertions.assertEquals(text.indexOf('\n') + 1, textArea.getCaretPosition()); + Assertions.assertEquals("\n", textArea.getSelectedText()); + } + + + @Test + void testActionPerformedImpl_noSelection_lettersAndNumbers() { RSyntaxTextArea textArea = new RSyntaxTextArea("line 1\nline 2\nline 3"); textArea.setCaretPosition(0); @@ -36,6 +155,38 @@ void testActionPerformedImpl_noSelection() { } + @Test + void testActionPerformedImpl_noSelection_symbolsWithTrailingWhitespace() { + + String text = "///// line 1\nline 2\nline 3"; + RSyntaxTextArea textArea = new RSyntaxTextArea(text); + textArea.setCaretPosition(0); + + ActionEvent e = new ActionEvent(textArea, 0, "command"); + new RSyntaxTextAreaEditorKit.NextWordAction("foo", false).actionPerformedImpl(e, textArea); + + // Skip the symbols and trailing whitespace to get to the next word + Assertions.assertEquals(text.indexOf("line 1"), textArea.getCaretPosition()); + Assertions.assertNull(textArea.getSelectedText()); + } + + + @Test + void testActionPerformedImpl_noSelection_symbolsAdjacentToNextWord() { + + String text = "/////line 1\nline 2\nline 3"; + RSyntaxTextArea textArea = new RSyntaxTextArea(text); + textArea.setCaretPosition(0); + + ActionEvent e = new ActionEvent(textArea, 0, "command"); + new RSyntaxTextAreaEditorKit.NextWordAction("foo", false).actionPerformedImpl(e, textArea); + + // Skip the symbols to get to the next word + Assertions.assertEquals(text.indexOf("line 1"), textArea.getCaretPosition()); + Assertions.assertNull(textArea.getSelectedText()); + } + + @Test void testActionPerformedImpl_noSelection_nextLine() { diff --git a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitPossiblyInsertTemplateActionTest.java b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitPossiblyInsertTemplateActionTest.java index 75e5fe71..0a490eab 100644 --- a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitPossiblyInsertTemplateActionTest.java +++ b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitPossiblyInsertTemplateActionTest.java @@ -5,6 +5,8 @@ package org.fife.ui.rsyntaxtextarea; import org.fife.ui.SwingRunnerExtension; +import org.fife.ui.rsyntaxtextarea.templates.CodeTemplate; +import org.fife.ui.rsyntaxtextarea.templates.StaticCodeTemplate; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; @@ -38,6 +40,21 @@ void tearDown() { } + @Test + void testActionPerformedImpl_notEditable() { + + String origContent = "line 1\nline 2\nline 3"; + RSyntaxTextArea textArea = new RSyntaxTextArea(origContent); + RSyntaxTextArea.setTemplatesEnabled(true); + textArea.setEditable(false); + + ActionEvent e = new ActionEvent(textArea, 0, "command"); + new RSyntaxTextAreaEditorKit.PossiblyInsertTemplateAction().actionPerformedImpl(e, textArea); + + Assertions.assertEquals(origContent, textArea.getText()); + } + + @Test void testActionPerformedImpl_notEnabled() { @@ -67,6 +84,24 @@ void testActionPerformedImpl_templatesNotEnabled() { } + @Test + void testActionPerformedImpl_templatesEnabled_matchingTemplate() { + + String origContent = "toReplace"; + RSyntaxTextArea textArea = new RSyntaxTextArea(origContent); + RSyntaxTextArea.setTemplatesEnabled(true); + CodeTemplate template = new StaticCodeTemplate("toReplace", "foo", "bar"); + RSyntaxTextArea.getCodeTemplateManager().addTemplate(template); + textArea.setCaretPosition(origContent.length()); + + ActionEvent e = new ActionEvent(textArea, 0, "command"); + new RSyntaxTextAreaEditorKit.PossiblyInsertTemplateAction().actionPerformedImpl(e, textArea); + + Assertions.assertEquals("foobar", textArea.getText()); + Assertions.assertEquals("foo".length(), textArea.getCaretPosition()); + } + + @Test void testActionPerformedImpl_templatesEnabled_noMatchingTemplate() { diff --git a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitPreviousWordActionTest.java b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitPreviousWordActionTest.java index 8e7cc61b..d15e13c9 100644 --- a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitPreviousWordActionTest.java +++ b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitPreviousWordActionTest.java @@ -23,7 +23,22 @@ class RSyntaxTextAreaEditorKitPreviousWordActionTest extends AbstractRSyntaxText @Test - void testActionPerformedImpl_noSelection() { + void testActionPerformedImpl_atOffset0() { + + String origContent = "line 1\nline 2\nline 3"; + RSyntaxTextArea textArea = new RSyntaxTextArea(origContent); + textArea.setCaretPosition(0); + + ActionEvent e = new ActionEvent(textArea, 0, "command"); + new RSyntaxTextAreaEditorKit.PreviousWordAction("foo", false).actionPerformedImpl(e, textArea); + + Assertions.assertEquals(0, textArea.getCaretPosition()); + Assertions.assertNull(textArea.getSelectedText()); + } + + + @Test + void testActionPerformedImpl_middleOfLine_noSelection_letters() { String origContent = "line 1\nline 2\nline 3"; RSyntaxTextArea textArea = new RSyntaxTextArea(origContent); @@ -38,7 +53,22 @@ void testActionPerformedImpl_noSelection() { @Test - void testActionPerformedImpl_noSelection_nextLine() { + void testActionPerformedImpl_middleOfLine_noSelection_symbols() { + + String origContent = "line 1\n@@@@ 2\nline 3"; + RSyntaxTextArea textArea = new RSyntaxTextArea(origContent); + textArea.setCaretPosition(origContent.indexOf('2')); + + ActionEvent e = new ActionEvent(textArea, 0, "command"); + new RSyntaxTextAreaEditorKit.PreviousWordAction("foo", false).actionPerformedImpl(e, textArea); + + Assertions.assertEquals(origContent.indexOf("@@@@ 2"), textArea.getCaretPosition()); + Assertions.assertNull(textArea.getSelectedText()); + } + + + @Test + void testActionPerformedImpl_middleOfLine_noSelection_nextLine() { RSyntaxTextArea textArea = new RSyntaxTextArea("line 1\nline 2\nline 3"); textArea.setCaretPosition(textArea.getText().indexOf('\n')); @@ -53,7 +83,7 @@ void testActionPerformedImpl_noSelection_nextLine() { @Test - void testActionPerformedImpl_selection() { + void testActionPerformedImpl_middleOfLine_selection() { String origContent = "line 1\nline 2\nline 3"; RSyntaxTextArea textArea = new RSyntaxTextArea(origContent); @@ -67,6 +97,56 @@ void testActionPerformedImpl_selection() { } + @Test + void testActionPerformedImpl_startOfLine_codeFolding_noSelection() { + + String origContent = "{\n exit(0);\n}"; + RSyntaxTextArea textArea = createTextArea(origContent); + textArea.setCaretPosition(origContent.indexOf('\n') + 1); + + ActionEvent e = new ActionEvent(textArea, 0, "command"); + new RSyntaxTextAreaEditorKit.PreviousWordAction("foo", false).actionPerformedImpl(e, textArea); + + // End of the previous line + Assertions.assertEquals(origContent.indexOf('\n'), textArea.getCaretPosition()); + Assertions.assertNull(textArea.getSelectedText()); + } + + + @Test + void testActionPerformedImpl_startOfLine_codeFolding_noSelection_hiddenLinesAbove() { + + // The caret is at the start of the last line. Lines immediately above it are collapsed. + String origContent = "{\n {\n foo;\n }\n}"; + RSyntaxTextArea textArea = createTextArea(origContent); + textArea.getFoldManager().getFold(0).getChild(0).setCollapsed(true); + textArea.setCaretPosition(origContent.lastIndexOf('\n') + 1); + + ActionEvent e = new ActionEvent(textArea, 0, "command"); + new RSyntaxTextAreaEditorKit.PreviousWordAction("foo", false).actionPerformedImpl(e, textArea); + + // End of the second line (where the collapsed section starts). + Assertions.assertEquals(origContent.indexOf(" {") + 3, textArea.getCaretPosition()); + Assertions.assertNull(textArea.getSelectedText()); + } + + + @Test + void testActionPerformedImpl_startOfLine_noCodeFolding_noSelection() { + + String origContent = "line 1\nline 2\nline 3"; + RSyntaxTextArea textArea = new RSyntaxTextArea(origContent); + textArea.setCaretPosition(origContent.indexOf("line 2")); + + ActionEvent e = new ActionEvent(textArea, 0, "command"); + new RSyntaxTextAreaEditorKit.PreviousWordAction("foo", false).actionPerformedImpl(e, textArea); + + // End of the previous line + Assertions.assertEquals(origContent.indexOf("1") + 1, textArea.getCaretPosition()); + Assertions.assertNull(textArea.getSelectedText()); + } + + @Test void testGetMacroID() { Assertions.assertEquals("foo", diff --git a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitTest.java b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitTest.java new file mode 100644 index 00000000..5118efed --- /dev/null +++ b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitTest.java @@ -0,0 +1,32 @@ +/* + * This library is distributed under a modified BSD license. See the included + * LICENSE file for details. + */ +package org.fife.ui.rsyntaxtextarea; + +import org.fife.ui.SwingRunnerExtension; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + + +/** + * Unit tests for the {@code RSyntaxTextAreaEditorKit} class. + * + * @author Robert Futrell + * @version 1.0 + */ +@ExtendWith(SwingRunnerExtension.class) +class RSyntaxTextAreaEditorKitTest { + + @Test + void testCreateDefaultDocument() { + RSyntaxTextAreaEditorKit kit = new RSyntaxTextAreaEditorKit(); + Assertions.assertInstanceOf(RSyntaxDocument.class, kit.createDefaultDocument()); + } + + @Test + void testGetString_validString() { + Assertions.assertNotNull(RSyntaxTextAreaEditorKit.getString("ContextMenu.Folding")); + } +} diff --git a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitToggleCommentActionTest.java b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitToggleCommentActionTest.java index 2504a9f9..42d706da 100644 --- a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitToggleCommentActionTest.java +++ b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitToggleCommentActionTest.java @@ -5,12 +5,11 @@ package org.fife.ui.rsyntaxtextarea; import org.fife.ui.SwingRunnerExtension; +import org.fife.ui.rtextarea.RecordableTextAction; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import java.awt.event.ActionEvent; - /** * Unit tests for the {@link RSyntaxTextAreaEditorKit.ToggleCommentAction} class. @@ -24,95 +23,119 @@ class RSyntaxTextAreaEditorKitToggleCommentActionTest extends AbstractRSyntaxTex @Test void testActionPerformedImpl_notEditable() { - - String code = "line 1\nline 2\nline 3"; - RSyntaxTextArea textArea = createTextArea(SyntaxConstants.SYNTAX_STYLE_C, - code); - textArea.setCaretPosition(8); + RSyntaxTextArea textArea = createTextArea(); textArea.setEditable(false); - - ActionEvent e = new ActionEvent(textArea, 0, "command"); - new RSyntaxTextAreaEditorKit.ToggleCommentAction().actionPerformedImpl(e, textArea); - - Assertions.assertEquals(code, textArea.getText()); + String origText = textArea.getText(); + RecordableTextAction a = new RSyntaxTextAreaEditorKit.ToggleCommentAction(); + a.actionPerformedImpl(null, textArea); + Assertions.assertEquals(origText, textArea.getText()); } @Test void testActionPerformedImpl_notEnabled() { - - String code = "line 1\nline 2\nline 3"; - RSyntaxTextArea textArea = createTextArea(SyntaxConstants.SYNTAX_STYLE_C, - code); - textArea.setCaretPosition(8); + RSyntaxTextArea textArea = createTextArea(); textArea.setEnabled(false); - - ActionEvent e = new ActionEvent(textArea, 0, "command"); - new RSyntaxTextAreaEditorKit.ToggleCommentAction().actionPerformedImpl(e, textArea); - - Assertions.assertEquals(code, textArea.getText()); + String origText = textArea.getText(); + RecordableTextAction a = new RSyntaxTextAreaEditorKit.ToggleCommentAction(); + a.actionPerformedImpl(null, textArea); + Assertions.assertEquals(origText, textArea.getText()); } @Test - void testActionPerformedImpl_singleLine_addComment() { - - RSyntaxTextArea textArea = createTextArea(SyntaxConstants.SYNTAX_STYLE_C, - "line 1\nline 2\nline 3"); - textArea.setCaretPosition(8); + void testActionPerformedImpl_add_multiLine_endsAtStartOfLine() { + String text = "line 1\nline 2\nline 3"; + RSyntaxTextArea textArea = createTextArea(text); + textArea.setCaretPosition(text.indexOf('1')); + textArea.moveCaretPosition(text.indexOf("line 3")); + RecordableTextAction a = new RSyntaxTextAreaEditorKit.ToggleCommentAction(); + a.actionPerformedImpl(null, textArea); + + // Final line is not commented out + String expected = "//line 1\n//line 2\nline 3"; + Assertions.assertEquals(expected, textArea.getText()); + } - ActionEvent e = new ActionEvent(textArea, 0, "command"); - new RSyntaxTextAreaEditorKit.ToggleCommentAction().actionPerformedImpl(e, textArea); - String expectedText = "line 1\n//line 2\nline 3"; - Assertions.assertEquals(expectedText, textArea.getText()); + @Test + void testActionPerformedImpl_add_multiLine_endsInMiddleOfLine() { + String text = "line 1\nline 2\nline 3"; + RSyntaxTextArea textArea = createTextArea(text); + textArea.setCaretPosition(text.indexOf('1')); + textArea.moveCaretPosition(text.indexOf("ne 3")); + RecordableTextAction a = new RSyntaxTextAreaEditorKit.ToggleCommentAction(); + a.actionPerformedImpl(null, textArea); + String expected = "//line 1\n//line 2\n//line 3"; + Assertions.assertEquals(expected, textArea.getText()); } @Test - void testActionPerformedImpl_singleLine_removeComment() { - - RSyntaxTextArea textArea = createTextArea(SyntaxConstants.SYNTAX_STYLE_C, - "line 1\n//line 2\nline 3"); - textArea.setCaretPosition(8); + void testActionPerformedImpl_add_singleLine_startTokenOnly() { + String text = "this is code"; + RSyntaxTextArea textArea = createTextArea(text); + textArea.setCaretPosition(0); + RecordableTextAction a = new RSyntaxTextAreaEditorKit.ToggleCommentAction(); + a.actionPerformedImpl(null, textArea); + Assertions.assertEquals("//" + text, textArea.getText()); + } - ActionEvent e = new ActionEvent(textArea, 0, "command"); - new RSyntaxTextAreaEditorKit.ToggleCommentAction().actionPerformedImpl(e, textArea); - String expectedText = "line 1\nline 2\nline 3"; - Assertions.assertEquals(expectedText, textArea.getText()); + @Test + void testActionPerformedImpl_add_singleLine_startAndEnd_missingEnd() { + String text = "", textArea.getText()); } @Test - void testActionPerformedImpl_multipleLines_addComment() { - - RSyntaxTextArea textArea = createTextArea(SyntaxConstants.SYNTAX_STYLE_C, - "line 1\nline 2\nline 3"); - textArea.setCaretPosition(2); - textArea.moveCaretPosition(8); + void testActionPerformedImpl_add_singleLine_languageWithoutComments() { + String text = "this is code"; + RSyntaxTextArea textArea = createTextArea(SyntaxConstants.SYNTAX_STYLE_BBCODE, text); + textArea.setCaretPosition(0); + RecordableTextAction a = new RSyntaxTextAreaEditorKit.ToggleCommentAction(); + a.actionPerformedImpl(null, textArea); + Assertions.assertEquals(text, textArea.getText()); + } - ActionEvent e = new ActionEvent(textArea, 0, "command"); - new RSyntaxTextAreaEditorKit.ToggleCommentAction().actionPerformedImpl(e, textArea); - String expectedText = "//line 1\n//line 2\nline 3"; - Assertions.assertEquals(expectedText, textArea.getText()); + @Test + void testActionPerformedImpl_remove_singleLine_caretAtStartOfLine() { + String text = "// this is code"; + RSyntaxTextArea textArea = createTextArea(text); + textArea.setCaretPosition(0); + RecordableTextAction a = new RSyntaxTextAreaEditorKit.ToggleCommentAction(); + a.actionPerformedImpl(null, textArea); + Assertions.assertEquals(" this is code", textArea.getText()); } @Test - void testActionPerformedImpl_multipleLines_removeComment() { - - RSyntaxTextArea textArea = createTextArea(SyntaxConstants.SYNTAX_STYLE_C, - "//line 1\n//line 2\nline 3"); - textArea.setCaretPosition(2); - textArea.moveCaretPosition(11); + void testActionPerformedImpl_remove_singleLine_caretAtStartOfLine_startAndEnd() { + String text = ""; + RSyntaxTextArea textArea = createTextArea(SyntaxConstants.SYNTAX_STYLE_XML, text); + textArea.setCaretPosition(0); + RecordableTextAction a = new RSyntaxTextAreaEditorKit.ToggleCommentAction(); + a.actionPerformedImpl(null, textArea); + Assertions.assertEquals(" this is code ", textArea.getText()); + } - ActionEvent e = new ActionEvent(textArea, 0, "command"); - new RSyntaxTextAreaEditorKit.ToggleCommentAction().actionPerformedImpl(e, textArea); - String expectedText = "line 1\nline 2\nline 3"; - Assertions.assertEquals(expectedText, textArea.getText()); + @Test + void testActionPerformedImpl_remove_singleLine_caretInMiddleOfLine() { + String text = "// this is code"; + RSyntaxTextArea textArea = createTextArea(text); + textArea.setCaretPosition(text.indexOf("is")); + RecordableTextAction a = new RSyntaxTextAreaEditorKit.ToggleCommentAction(); + a.actionPerformedImpl(null, textArea); + Assertions.assertEquals(" this is code", textArea.getText()); } diff --git a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitToggleCurrentFoldActionTest.java b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitToggleCurrentFoldActionTest.java index 48c06608..e1f3cedb 100644 --- a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitToggleCurrentFoldActionTest.java +++ b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/RSyntaxTextAreaEditorKitToggleCurrentFoldActionTest.java @@ -10,6 +10,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import javax.swing.*; import java.awt.event.ActionEvent; @@ -22,6 +23,19 @@ @ExtendWith(SwingRunnerExtension.class) class RSyntaxTextAreaEditorKitToggleCurrentFoldActionTest extends AbstractRSyntaxTextAreaTest { + @Test + void testConstructor_5Arg() { + Action a = new RSyntaxTextAreaEditorKit.ToggleCurrentFoldAction( + "name", null, "desc", 1, null + ); + Assertions.assertEquals("name", a.getValue(Action.NAME)); + Assertions.assertNull(a.getValue(Action.LARGE_ICON_KEY)); + Assertions.assertNull(a.getValue(Action.SMALL_ICON)); + Assertions.assertEquals("desc", a.getValue(Action.SHORT_DESCRIPTION)); + Assertions.assertEquals(1, a.getValue(Action.MNEMONIC_KEY)); + Assertions.assertNull(a.getValue(Action.ACCELERATOR_KEY)); + } + @Test void testActionPerformedImpl_happyPath() { @@ -38,6 +52,20 @@ void testActionPerformedImpl_happyPath() { } + @Test + void testActionPerformedImpl_noFoldsInDocument() { + + RSyntaxTextArea textArea = createTextArea("this is code"); + textArea.setCaretPosition(1); + + ActionEvent e = new ActionEvent(textArea, 0, "command"); + new RSyntaxTextAreaEditorKit.ToggleCurrentFoldAction().actionPerformedImpl(e, textArea); + + FoldManager foldManager = textArea.getFoldManager(); + Assertions.assertEquals(0, foldManager.getFoldCount()); + } + + @Test void testActionPerformedImpl_foldingDisabled() { diff --git a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/TokenIteratorTest.java b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/TokenIteratorTest.java index f46c48af..04ea925a 100755 --- a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/TokenIteratorTest.java +++ b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/TokenIteratorTest.java @@ -85,6 +85,17 @@ void testEmptyLines() throws Exception { } + @Test + void testRemove() { + Assertions.assertThrows(UnsupportedOperationException.class, () -> { + RSyntaxDocument doc = loadResource("TokenIteratorTest_JavaBasic.txt", + SyntaxConstants.SYNTAX_STYLE_JAVA); + TokenIterator iter = new TokenIterator(doc); + iter.remove(); + }); + } + + /** * Loads a text resource from the classpath into an instance of * {@link RSyntaxDocument}. diff --git a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/URLFileLocationTest.java b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/URLFileLocationTest.java new file mode 100644 index 00000000..2cf36090 --- /dev/null +++ b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/URLFileLocationTest.java @@ -0,0 +1,65 @@ +/* + * This library is distributed under a modified BSD license. See the included + * LICENSE file for details. + */ +package org.fife.ui.rsyntaxtextarea; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + + +/** + * Unit tests for the {@link URLFileLocation} class. + * + * @author Robert Futrell + * @version 1.0 + */ +class URLFileLocationTest { + + + @Test + void testGetActualLastModified() { + String url = "https://google.com"; + FileLocation loc = FileLocation.create(url); + Assertions.assertInstanceOf(URLFileLocation.class, loc); + Assertions.assertEquals(TextEditorPane.LAST_MODIFIED_UNKNOWN, loc.getActualLastModified()); + } + + + @Test + void testGetFileFullPath() { + String url = "https://google.com"; + FileLocation loc = FileLocation.create(url); + Assertions.assertInstanceOf(URLFileLocation.class, loc); + Assertions.assertEquals(url, loc.getFileFullPath()); + } + + + @Test + void testGetFileName() { + String url = "https://google.com"; + FileLocation loc = FileLocation.create(url); + Assertions.assertInstanceOf(URLFileLocation.class, loc); + Assertions.assertEquals("", loc.getFileName()); + } + + + @Test + void testIsLocal_https() { + String url = "https://google.com"; + FileLocation loc = FileLocation.create(url); + Assertions.assertInstanceOf(URLFileLocation.class, loc); + Assertions.assertFalse(loc.isLocal()); + } + + + @Test + void testIsLocalAndExists() { + String url = "https://google.com"; + FileLocation loc = FileLocation.create(url); + Assertions.assertInstanceOf(URLFileLocation.class, loc); + Assertions.assertFalse(loc.isLocalAndExists()); + } + + +} diff --git a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/focusabletip/TipWindowTest.java b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/focusabletip/TipWindowTest.java new file mode 100644 index 00000000..6f6f2ef8 --- /dev/null +++ b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/focusabletip/TipWindowTest.java @@ -0,0 +1,117 @@ +/* + * This library is distributed under a modified BSD license. See the included + * LICENSE file for details. + */ +package org.fife.ui.rsyntaxtextarea.focusabletip; + +import org.fife.ui.SwingRunnerExtension; +import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import javax.swing.*; +import java.io.IOException; +import java.net.URL; + + +/** + * Unit tests for the {@link TipWindow} class. + * + * @author Robert Futrell + * @version 1.0 + */ +@ExtendWith(SwingRunnerExtension.class) +class TipWindowTest { + + @Test + void testConstructor_nullTitle() { + JFrame owner = new JFrame(); + RSyntaxTextArea textArea = new RSyntaxTextArea(); + FocusableTip focusableTip = new FocusableTipTest.TestableFocusableTip(textArea, null); + + TipWindow tw = new TipWindow(owner, focusableTip, null); + Assertions.assertTrue(tw.getText().startsWith("")); + Assertions.assertFalse(tw.getText().contains("null")); + } + + @Test + void testConstructor_title_short() { + JFrame owner = new JFrame(); + RSyntaxTextArea textArea = new RSyntaxTextArea(); + FocusableTip focusableTip = new FocusableTipTest.TestableFocusableTip(textArea, null); + + TipWindow tw = new TipWindow(owner, focusableTip, "test"); + Assertions.assertTrue(tw.getText().startsWith("")); + Assertions.assertTrue(tw.getText().contains("test")); + } + + @Test + void testConstructor_title_long_plainText() { + JFrame owner = new JFrame(); + RSyntaxTextArea textArea = new RSyntaxTextArea(); + FocusableTip focusableTip = new FocusableTipTest.TestableFocusableTip(textArea, null); + + String text = "A very long string of content"; + TipWindow tw = new TipWindow(owner, focusableTip, text); + Assertions.assertTrue(tw.getText().startsWith("")); + Assertions.assertTrue(tw.getText().contains(text)); + } + + @Test + void testConstructor_title_long_plainText_escapedForHtml() { + JFrame owner = new JFrame(); + RSyntaxTextArea textArea = new RSyntaxTextArea(); + FocusableTip focusableTip = new FocusableTipTest.TestableFocusableTip(textArea, null); + + String text = "A very long string of content"; + TipWindow tw = new TipWindow(owner, focusableTip, text); + Assertions.assertTrue(tw.getText().startsWith("")); + Assertions.assertTrue(tw.getText().contains("A very <em>long</em> string of content")); + } + + @Test + void testConstructor_title_long_html() { + JFrame owner = new JFrame(); + RSyntaxTextArea textArea = new RSyntaxTextArea(); + FocusableTip focusableTip = new FocusableTipTest.TestableFocusableTip(textArea, null); + + String text = "This rocks!"; + TipWindow tw = new TipWindow(owner, focusableTip, text); + Assertions.assertTrue(tw.getText().startsWith("")); + Assertions.assertTrue(tw.getText().contains("This rocks!")); + } + + @Test + void testConstructor_imageBaseInstalledOnTextArea() throws IOException { + JFrame owner = new JFrame(); + RSyntaxTextArea textArea = new RSyntaxTextArea(); + FocusableTip focusableTip = new FocusableTipTest.TestableFocusableTip(textArea, null); + focusableTip.setImageBase(new URL("https://google.com")); + + new TipWindow(owner, focusableTip, "test"); + } + + @Test + void testActionPerformed() throws IOException { + JFrame owner = new JFrame(); + RSyntaxTextArea textArea = new RSyntaxTextArea(); + FocusableTip focusableTip = new FocusableTipTest.TestableFocusableTip(textArea, null); + + TipWindow tw = new TipWindow(owner, focusableTip, "test"); + tw.actionPerformed(); + } + + @Test + void testGetSetHyperlinkListener() throws IOException { + JFrame owner = new JFrame(); + RSyntaxTextArea textArea = new RSyntaxTextArea(); + FocusableTip focusableTip = new FocusableTipTest.TestableFocusableTip(textArea, null); + focusableTip.setImageBase(new URL("https://google.com")); + + TipWindow tw = new TipWindow(owner, focusableTip, "test"); + tw.setHyperlinkListener(e -> {}); + tw.setHyperlinkListener(null); + tw.setHyperlinkListener(e -> {}); + } +} diff --git a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/modes/PerlTokenMakerTest.java b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/modes/PerlTokenMakerTest.java index 69adaaaa..7cb9c753 100755 --- a/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/modes/PerlTokenMakerTest.java +++ b/RSyntaxTextArea/src/test/java/org/fife/ui/rsyntaxtextarea/modes/PerlTokenMakerTest.java @@ -24,6 +24,36 @@ class PerlTokenMakerTest extends AbstractCDerivedTokenMakerTest { + private void assertAllSecondTokensAreRegexes(String... codes) { + for (String code : codes) { + + Segment segment = createSegment(code); + TokenMaker tm = createTokenMaker(); + Token token = tm.getTokenList(segment, TokenTypes.NULL, 0); + + // Skip the first token + token = token.getNextToken(); + Assertions.assertEquals(TokenTypes.REGEX, token.getType(), "not a regex: " + + token + " (code snippet: \"" + code + "\""); + } + } + + + private void assertAllSecondTokensAreNotRegexes(String... codes) { + for (String code : codes) { + + Segment segment = createSegment(code); + TokenMaker tm = createTokenMaker(); + Token token = tm.getTokenList(segment, TokenTypes.NULL, 0); + + // Skip the first token + token = token.getNextToken(); + Assertions.assertNotEquals(TokenTypes.REGEX, token.getType(), "is a regex: " + + token + " (code snippet: \"" + code + "\""); + } + } + + @Override protected TokenMaker createTokenMaker() { return new PerlTokenMaker(); @@ -51,6 +81,38 @@ public void testCommon_getMarkOccurrencesOfTokenType() { } + @Test + void testBacktickLiterals() { + assertAllTokensOfType(TokenTypes.LITERAL_BACKQUOTE, + "``", + "`hi`", + "`\\u00fe`", + "`\\``" + ); + } + + + @Test + void testBacktickLiterals_continuedFromPriorLine() { + assertAllTokensOfType(TokenTypes.LITERAL_BACKQUOTE, + TokenTypes.LITERAL_BACKQUOTE, + "continued from prior line", + "continued from prior line\"" + ); + } + + + @Test + void testBacktickLiterals_unclosed() { + assertAllTokensOfType(TokenTypes.LITERAL_BACKQUOTE, + "`", + "`hi there", + "`\\u00fe", + "`\\` unclosed" + ); + } + + @Test void testCharLiterals() { @@ -71,6 +133,27 @@ void testCharLiterals() { } + @Test + void testCharLiterals_continuedFromPriorLine() { + assertAllTokensOfType(TokenTypes.LITERAL_CHAR, + TokenTypes.LITERAL_CHAR, + "continued from prior line", + "continued from prior line'" + ); + } + + + @Test + void testCharLiterals_unclosed() { + assertAllTokensOfType(TokenTypes.LITERAL_CHAR, + "'", + "'hi there", + "'\\u00fe", + "'\\' unclosed" + ); + } + + @Test void testEolComments() { @@ -130,6 +213,206 @@ void testFloatingPointLiterals() { } + @Test + void testHeredoc_eot_doubleQuoted() { + assertAllTokensOfType(TokenTypes.PREPROCESSOR, + "<<\"EOT\"", + "<<\"EOT\" this is heredoc", + "<<\"EOT\" this is heredoc EOT", + "<<\"EOT\" this is heredoc with escaped chars \\EEOT", + "<<\"EOT\" heredoc with $ dollar sign not part of variable" + ); + } + + + @Test + void testHeredoc_eot_doubleQuoted_fromPriorLine() { + assertAllTokensOfType(TokenTypes.PREPROCESSOR, + // State is reused here since it's identical in these two cases + PerlTokenMaker.INTERNAL_HEREDOC_EOT_UNQUOTED, + "more heredoc", + "more heredoc", + "more heredoc with escaped chars \\EEOT", + "more heredoc with $ dollar sign not part of variable", + "unterminated EOT", + "EOT" + ); + } + + + @Test + void testHeredoc_eot_singleQuoted() { + assertAllTokensOfType(TokenTypes.PREPROCESSOR, + "<<'EOT'", + "<<'EOT' this is heredoc", + "<<'EOT' this is heredoc EOT", + "<<'EOT' this is heredoc with escaped chars \\EEOT", + "<<'EOT' heredoc with $ dollar sign not part of variable" + ); + } + + + @Test + void testHeredoc_eot_singleQuoted_fromPriorLine() { + assertAllTokensOfType(TokenTypes.PREPROCESSOR, + PerlTokenMaker.INTERNAL_HEREDOC_EOT_SINGLE_QUOTED, + "more heredoc", + "more heredoc", + "more heredoc with escaped chars \\EEOT", + "more heredoc with $ dollar sign not part of variable", + "unterminated EOT", + "EOT" + ); + } + + + @Test + void testHeredoc_eot_unquoted() { + assertAllTokensOfType(TokenTypes.PREPROCESSOR, + "<>=/foo/", + "~/foo/", + "!~/foo/" + ); + } + + + @Test + void testRegex_notWhenFollowingCertainTokens() { + assertAllSecondTokensAreNotRegexes( + "^/foo/", + ">>/foo/", + "<