diff options
author | simonbrandhof <simon.brandhof@gmail.com> | 2010-09-06 14:08:06 +0000 |
---|---|---|
committer | simonbrandhof <simon.brandhof@gmail.com> | 2010-09-06 14:08:06 +0000 |
commit | aeadc1f9129274949daaa57738c7c4550bdfbc7b (patch) | |
tree | 08dadf5ef7474fc41d1d48f74648f1ba8b55f34d /sonar-channel | |
download | sonarqube-aeadc1f9129274949daaa57738c7c4550bdfbc7b.tar.gz sonarqube-aeadc1f9129274949daaa57738c7c4550bdfbc7b.zip |
SONAR-236 remove deprecated code from checkstyle plugin + display default value of rule parameters in Q profile console
Diffstat (limited to 'sonar-channel')
9 files changed, 858 insertions, 0 deletions
diff --git a/sonar-channel/pom.xml b/sonar-channel/pom.xml new file mode 100644 index 00000000000..f4e0c5891fc --- /dev/null +++ b/sonar-channel/pom.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.codehaus.sonar</groupId> + <artifactId>sonar</artifactId> + <version>2.3-SNAPSHOT</version> + <relativePath>..</relativePath> + </parent> + <artifactId>sonar-channel</artifactId> + <name>Sonar :: Channel</name> + <description>Code Channel</description> + + <dependencies> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest-all</artifactId> + <scope>test</scope> + </dependency> + </dependencies> +</project>
\ No newline at end of file diff --git a/sonar-channel/src/main/java/org/sonar/channel/Channel.java b/sonar-channel/src/main/java/org/sonar/channel/Channel.java new file mode 100644 index 00000000000..198ad995f61 --- /dev/null +++ b/sonar-channel/src/main/java/org/sonar/channel/Channel.java @@ -0,0 +1,25 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.channel; + +public abstract class Channel<OUTPUT> { + + public abstract boolean consume(CodeReader code, OUTPUT output); +} diff --git a/sonar-channel/src/main/java/org/sonar/channel/ChannelDispatcher.java b/sonar-channel/src/main/java/org/sonar/channel/ChannelDispatcher.java new file mode 100644 index 00000000000..f307c2c3335 --- /dev/null +++ b/sonar-channel/src/main/java/org/sonar/channel/ChannelDispatcher.java @@ -0,0 +1,68 @@ +/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2009 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+
+package org.sonar.channel;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ChannelDispatcher<OUTPUT> extends Channel<OUTPUT> {
+
+ private static final Logger logger = LoggerFactory.getLogger(ChannelDispatcher.class);
+ private final boolean failIfNoChannelToConsumeOneCharacter;
+
+ private final Channel[] channels;
+
+ public ChannelDispatcher(List<Channel> tokenizers) {
+ this(tokenizers, false);
+ }
+
+ public ChannelDispatcher(List<Channel> tokenizers, boolean failIfNoChannelToConsumeOneCharacter) {
+ this.channels = tokenizers.toArray(new Channel[0]); // NOSONAR, lack of performance is not an issue here
+ this.failIfNoChannelToConsumeOneCharacter = failIfNoChannelToConsumeOneCharacter;
+ }
+
+ public boolean consume(CodeReader code, OUTPUT output) {
+ int nextChar = code.peek();
+ while (nextChar != -1) {
+ boolean channelConsumed = false;
+ for (Channel<OUTPUT> channel : channels) {
+ if (channel.consume(code, output)) {
+ channelConsumed = true;
+ break;
+ }
+ }
+ if ( !channelConsumed) {
+ String message = "None of the channel has been able to handle character '" + (char) code.peek() + "' (decimal value " + code.peek()
+ + ") at line "
+ + code.getLinePosition() + ", column " + code.getColumnPosition();
+ if (failIfNoChannelToConsumeOneCharacter) {
+ throw new IllegalStateException(message);
+ }
+ logger.debug(message);
+ code.pop();
+ }
+ nextChar = code.peek();
+ }
+ return true;
+ }
+}
\ No newline at end of file diff --git a/sonar-channel/src/main/java/org/sonar/channel/ChannelException.java b/sonar-channel/src/main/java/org/sonar/channel/ChannelException.java new file mode 100644 index 00000000000..1b1f4c9f3d0 --- /dev/null +++ b/sonar-channel/src/main/java/org/sonar/channel/ChannelException.java @@ -0,0 +1,31 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.channel; + +public class ChannelException extends RuntimeException { + + public ChannelException(String message, Exception e) { + super(message, e); + } + + public ChannelException(String message) { + super(message); + } +} diff --git a/sonar-channel/src/main/java/org/sonar/channel/CodeBuffer.java b/sonar-channel/src/main/java/org/sonar/channel/CodeBuffer.java new file mode 100644 index 00000000000..f726f0a9645 --- /dev/null +++ b/sonar-channel/src/main/java/org/sonar/channel/CodeBuffer.java @@ -0,0 +1,251 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.channel; + +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; + +import org.apache.commons.io.IOUtils; + +/** + * The CodeBuffer class provides all the basic features required to manipulate a source code character stream. + * Those features are : + * <ul> + * <li>Read and consume next source code character : pop()</li> + * <li>Retrieve last consumed character : lastChar()</li> + * <li>Read without consuming next source code character : peek()</li> + * <li>Read without consuming character at the specified index after the cursor</li> + * <li>Position of the pending cursor : line and column</li> + * </ul> + */ +public class CodeBuffer implements CharSequence { + + private final Reader code; + private int lastChar = -1; + private Cursor cursor; + private final static int DEFAULT_BUFFER_CAPACITY = 8000; + private int bufferCapacity; + private char[] buffer; + private int bufferPosition = 0; + private int bufferSize = 0; + private static final char LF = '\n'; + private static final char CR = '\r'; + private boolean recordingMode = false; + private StringBuilder recordedCharacters = new StringBuilder(); + + public CodeBuffer(Reader code) { + this(code, DEFAULT_BUFFER_CAPACITY); + } + + private CodeBuffer(Reader code, int bufferCapacity) { + this.code = code; + lastChar = -1; + cursor = new Cursor(); + this.bufferCapacity = bufferCapacity; + buffer = new char[bufferCapacity]; + fillBuffer(); + } + + public CodeBuffer(String code) { + this(new StringReader(code)); + } + + protected CodeBuffer(String code, int bufferCapacity) { + this(new StringReader(code), bufferCapacity); + } + + /** + * Read and consume the next character + * + * @return the next character or -1 if the end of the stream is reached + */ + public final int pop() { + if (bufferPosition == bufferSize) { + fillBuffer(); + } + if (bufferSize == 0) { + return -1; + } + int character = buffer[bufferPosition++]; + if (character == LF || character == CR) { + if ((lastChar != LF && lastChar != CR) || lastChar == character || lastChar == LF) { + cursor.line++; + } + cursor.column = 0; + } else { + cursor.column++; + } + if (recordingMode) { + recordedCharacters.append((char) character); + } + lastChar = character; + return character; + } + + private int fillBuffer() { + try { + int offset = bufferSize - bufferPosition; + if (offset != 0) { + System.arraycopy(buffer, bufferPosition, buffer, 0, bufferSize - bufferPosition); + } + bufferPosition = 0; + int numberOfChars = code.read(buffer, offset, bufferCapacity - offset); + if (numberOfChars == -1) { + numberOfChars = 0; + } + bufferSize = numberOfChars + offset; + return offset; + } catch (IOException e) { + throw new ChannelException(e.getMessage(), e); + } + } + + /** + * Get the last consumed character + * + * @return the last character or -1 if the no character has been yet consumed + */ + public final int lastChar() { + return lastChar; + } + + /** + * Read without consuming the next character + * + * @return the next character or -1 if the end of the stream is reached + */ + public final int peek() { + return intAt(0); + } + + /** + * Close the stream + */ + public final void close() { + IOUtils.closeQuietly(code); + } + + /** + * @return the current line of the cursor + */ + public final int getLinePosition() { + return cursor.line; + } + + public final Cursor getCursor() { + return cursor; + } + + /** + * @return the current column of the cursor + */ + public final int getColumnPosition() { + return cursor.column; + } + + /** + * Overrides the current column position + */ + public final CodeBuffer setColumnPosition(int cp) { + this.cursor.column = cp; + return this; + } + + /** + * Overrides the current line position + */ + public final void setLinePosition(int lp) { + this.cursor.line = lp; + } + + public final void startRecording() { + recordingMode = true; + } + + public final CharSequence stopRecording() { + recordingMode = false; + CharSequence result = recordedCharacters; + recordedCharacters = new StringBuilder(); + return result; + } + + /** + * Returns the character at the specified index after the cursor without consuming it + * + * @param index + * the index of the character to be returned + * @return the desired character + * @see java.lang.CharSequence#charAt(int) + */ + public final char charAt(int index) { + return (char) intAt(index); + } + + protected final int intAt(int index) { + if (bufferPosition + index > bufferSize - 1) { + fillBuffer(); + } + if (bufferPosition + index > bufferSize - 1) { + return -1; + } + return buffer[bufferPosition + index]; + } + + public final int length() { + return bufferSize; + } + + public final CharSequence subSequence(int start, int end) { + throw new UnsupportedOperationException(); + } + + @Override + public final String toString() { + StringBuilder result = new StringBuilder(); + result.append("CodeReader("); + result.append("line:" + cursor.line); + result.append("|column:" + cursor.column); + result.append("|cursor value:'" + (char) peek() + "'"); + result.append(")"); + return result.toString(); + } + + public final class Cursor { + + private int line = 1; + private int column = 0; + + public int getLine() { + return line; + } + + public int getColumn() { + return column; + } + + public Cursor clone() { + Cursor clone = new Cursor(); + clone.column = column; + clone.line = line; + return clone; + } + } +} diff --git a/sonar-channel/src/main/java/org/sonar/channel/CodeReader.java b/sonar-channel/src/main/java/org/sonar/channel/CodeReader.java new file mode 100644 index 00000000000..f894ca7fd15 --- /dev/null +++ b/sonar-channel/src/main/java/org/sonar/channel/CodeReader.java @@ -0,0 +1,180 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.channel; + +import java.io.IOException; +import java.io.Reader; +import java.util.regex.Matcher; + +/** + * The CodeReader class provides all the basic features to lex a source code. + * Those features are : + * <ul> + * <li>Read and consume next characters until a regular expression is matched</li> + * </ul> + */ +public class CodeReader extends CodeBuffer { + + private Cursor previousCursor; + + public CodeReader(Reader code) { + super(code); + } + + public CodeReader(String code) { + super(code); + } + + protected CodeReader(String code, int bufferCapacity) { + super(code, bufferCapacity); + } + + /** + * Read and consume the next character + * + * @param appendable + * the read character is appended to appendable + */ + public final void pop(Appendable appendable) { + try { + appendable.append((char) pop()); + } catch (IOException e) { + throw new ChannelException(e.getMessage()); + } + } + + /** + * Read without consuming the next characters + * + * @param length + * number of character to read + * @return array of characters + */ + public final char[] peek(int length) { + char[] result = new char[length]; + int index = 0; + int nextChar = intAt(index); + while (nextChar != -1 && index < length) { + result[index] = (char) nextChar; + nextChar = intAt(++index); + } + return result; + } + + /** + * Read without consuming the next characters until a condition is reached (EndMatcher) + * + * @param matcher + * the EndMatcher used to stop the reading + * @param appendable + * the read characters is appended to appendable + */ + public final void peekTo(EndMatcher matcher, Appendable appendable) { + int index = 0; + char nextChar = charAt(index); + try { + while ( !matcher.match(nextChar) && nextChar != -1) { + appendable.append(nextChar); + nextChar = charAt(++index); + } + } catch (IOException e) { + throw new ChannelException(e.getMessage(), e); + } + } + + /** + * @deprecated see peekTo(EndMatcher matcher, Appendable appendable) + */ + @Deprecated + public final String peekTo(EndMatcher matcher) { + StringBuilder sb = new StringBuilder(); + peekTo(matcher, sb); + return sb.toString(); + } + + /** + * @deprecated see popTo(Matcher matcher, Appendable appendable) + */ + @Deprecated + public final void popTo(EndMatcher matcher, Appendable appendable) { + previousCursor = getCursor().clone(); + try { + do { + appendable.append((char) pop()); + } while ( !matcher.match(peek()) && peek() != -1); + } catch (IOException e) { + throw new ChannelException(e.getMessage(), e); + } + } + + /** + * Read and consume the next characters according to a given regular expression + * + * @param matcher + * the regular expression matcher + * @param appendable + * the consumed characters are appended to this appendable + * @return number of consumed characters or -1 if the next input sequence doesn't match this matcher's pattern + */ + public final int popTo(Matcher matcher, Appendable appendable) { + return popTo(matcher, null, appendable); + } + + /** + * Read and consume the next characters according to a given regular expression. Moreover the character sequence immediately following the + * desired characters must also match a given regular expression. + * + * @param matcher + * the Matcher used to try consuming next characters + * @param afterMatcher + * the Matcher used to check character sequence immediately following the consumed characters + * @param appendable + * the consumed characters are appended to this appendable + * @return number of consumed characters or -1 if one of the two Matchers doesn't match + */ + public final int popTo(Matcher matcher, Matcher afterMatcher, Appendable appendable) { + try { + matcher.reset(this); + if (matcher.lookingAt()) { + if (afterMatcher != null) { + afterMatcher.reset(this); + afterMatcher.region(matcher.end(), length()); + if ( !afterMatcher.lookingAt()) { + return -1; + } + } + previousCursor = getCursor().clone(); + for (int i = 0; i < matcher.end(); i++) { + appendable.append((char) pop()); + } + return matcher.end(); + } + } catch (IndexOutOfBoundsException e) { + return -1; + } catch (IOException e) { + throw new ChannelException(e.getMessage(), e); + } + return -1; + } + + public final Cursor getPreviousCursor() { + return previousCursor; + } +} diff --git a/sonar-channel/src/main/java/org/sonar/channel/EndMatcher.java b/sonar-channel/src/main/java/org/sonar/channel/EndMatcher.java new file mode 100644 index 00000000000..e74d2b76643 --- /dev/null +++ b/sonar-channel/src/main/java/org/sonar/channel/EndMatcher.java @@ -0,0 +1,25 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.channel; + +public interface EndMatcher { + + boolean match(int toMatch); +} diff --git a/sonar-channel/src/test/java/org/sonar/channel/CodeBufferTest.java b/sonar-channel/src/test/java/org/sonar/channel/CodeBufferTest.java new file mode 100644 index 00000000000..eedf28ae0ad --- /dev/null +++ b/sonar-channel/src/test/java/org/sonar/channel/CodeBufferTest.java @@ -0,0 +1,119 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.channel; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import org.junit.Test; + +public class CodeBufferTest { + + @Test + public void testPop() { + CodeBuffer code = new CodeBuffer("pa"); + assertThat((char) code.pop(), is('p')); + assertThat((char) code.pop(), is('a')); + assertThat(code.pop(), is( -1)); + } + + @Test + public void testPeek() { + CodeBuffer code = new CodeBuffer("pa"); + assertThat((char) code.peek(), is('p')); + assertThat((char) code.peek(), is('p')); + code.pop(); + assertThat((char) code.peek(), is('a')); + code.pop(); + assertThat(code.peek(), is( -1)); + } + + @Test + public void testLastCharacter() { + CodeReader reader = new CodeReader("bar"); + assertThat(reader.lastChar(), is( -1)); + reader.pop(); + assertThat((char) reader.lastChar(), is('b')); + } + + @Test + public void testGetColumnAndLinePosition() { + CodeReader reader = new CodeReader("pa\nc\r\ns\r\n\r\n"); + assertThat(reader.getColumnPosition(), is(0)); + assertThat(reader.getLinePosition(), is(1)); + reader.pop(); // p + reader.pop(); // a + assertThat(reader.getColumnPosition(), is(2)); + assertThat(reader.getLinePosition(), is(1)); + reader.peek(); // \n + reader.lastChar(); // a + assertThat(reader.getColumnPosition(), is(2)); + assertThat(reader.getLinePosition(), is(1)); + reader.pop(); // \n + assertThat(reader.getColumnPosition(), is(0)); + assertThat(reader.getLinePosition(), is(2)); + reader.pop(); // c + assertThat(reader.getColumnPosition(), is(1)); + assertThat(reader.getLinePosition(), is(2)); + reader.pop(); // \r + reader.pop(); // \n + assertThat(reader.getColumnPosition(), is(0)); + assertThat(reader.getLinePosition(), is(3)); + assertThat((char) reader.pop(), is('s')); + reader.pop(); // \r + assertThat(reader.getColumnPosition(), is(0)); + assertThat(reader.getLinePosition(), is(4)); + reader.pop(); // \n + assertThat(reader.getColumnPosition(), is(0)); + assertThat(reader.getLinePosition(), is(4)); + reader.pop(); // \r + reader.pop(); // \n + assertThat(reader.getColumnPosition(), is(0)); + assertThat(reader.getLinePosition(), is(5)); + } + + @Test + public void testStartAndStopRecording() { + CodeReader reader = new CodeReader("123456"); + reader.pop(); + assertEquals("", reader.stopRecording().toString()); + + reader.startRecording(); + reader.pop(); + reader.pop(); + reader.peek(); + assertEquals("23", reader.stopRecording().toString()); + assertEquals("", reader.stopRecording().toString()); + } + + @Test + public void testCharAt() { + CodeReader reader = new CodeReader("123456"); + assertEquals('1', reader.charAt(0)); + assertEquals('6', reader.charAt(5)); + } + + @Test + public void testCharAtIndexOutOfBoundsException() { + CodeReader reader = new CodeReader("12345"); + assertEquals(reader.charAt(5), (char) -1); + } +} diff --git a/sonar-channel/src/test/java/org/sonar/channel/CodeReaderTest.java b/sonar-channel/src/test/java/org/sonar/channel/CodeReaderTest.java new file mode 100644 index 00000000000..7c195bff527 --- /dev/null +++ b/sonar-channel/src/test/java/org/sonar/channel/CodeReaderTest.java @@ -0,0 +1,125 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.channel; + +import static org.hamcrest.core.Is.is; +import static org.hamcrest.number.OrderingComparisons.lessThan; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import java.io.StringReader; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.junit.Test; + +public class CodeReaderTest { + + @Test + public void testPopWithAppendable() { + CodeReader reader = new CodeReader("package org.sonar;"); + + StringBuilder sw = new StringBuilder(); + reader.pop(sw); + assertEquals("p", sw.toString()); + reader.pop(sw); + assertEquals("pa", sw.toString()); + + } + + @Test + public void testPeekACharArray() { + CodeReader reader = new CodeReader(new StringReader("bar")); + char[] chars = reader.peek(2); + assertThat(chars.length, is(2)); + assertThat(chars[0], is('b')); + assertThat(chars[1], is('a')); + } + + @Test + public void testPeekTo() { + CodeReader reader = new CodeReader(new StringReader("package org.sonar;")); + StringBuilder result = new StringBuilder(); + reader.peekTo(new EndMatcher() { + + public boolean match(int endFlag) { + return 'r' == (char) endFlag; + } + }, result); + assertEquals("package o", result.toString()); + assertThat(reader.peek(), is((int) 'p')); // never called pop() + } + + @Test + public void testPopTo() { + CodeReader reader = new CodeReader(new StringReader("package org.sonar;")); + StringBuilder result = new StringBuilder(); + reader.popTo(new EndMatcher() { + + public boolean match(int endFlag) { + return 'r' == (char) endFlag; + } + }, result); + assertThat(result.toString(), is("package o")); + assertThat(reader.peek(), is((int) 'r')); + CodeReader.Cursor previousCursor = reader.getPreviousCursor(); + assertThat(previousCursor.getColumn(), is(0)); + assertThat(previousCursor.getLine(), is(1)); + } + + @Test + public void testPeekToAndReachingTheBufferLimit() { + CodeReader reader = new CodeReader("word1 word2 word2", 10); + for (int i = 0; i < 6; i++) { + reader.pop(); + } + StringBuilder result = new StringBuilder(); + reader.peekTo(new EndMatcher() { + + public boolean match(int endFlag) { + return ' ' == (char) endFlag; + } + }, result); + assertEquals("word2", result.toString()); + } + + @Test + public void testPopToWithRegex() { + CodeReader reader = new CodeReader(new StringReader("123ABC")); + StringBuilder token = new StringBuilder(); + assertEquals(3, reader.popTo(Pattern.compile("\\d+").matcher(new String()), token)); + assertEquals("123", token.toString()); + assertEquals( -1, reader.popTo(Pattern.compile("\\d+").matcher(new String()), token)); + assertEquals(3, reader.popTo(Pattern.compile("\\w+").matcher(new String()), token)); + assertEquals("123ABC", token.toString()); + assertEquals( -1, reader.popTo(Pattern.compile("\\w+").matcher(new String()), token)); + } + + @Test + public void testPopToWithRegexAndFollowingMatcher() { + Matcher digitMatcher = Pattern.compile("\\d+").matcher(new String()); + Matcher alphabeticMatcher = Pattern.compile("[a-zA-Z]").matcher(new String()); + StringBuilder token = new StringBuilder(); + assertEquals( -1, new CodeReader(new StringReader("123 ABC")).popTo(digitMatcher, alphabeticMatcher, token)); + assertEquals("", token.toString()); + assertEquals(3, new CodeReader(new StringReader("123ABC")).popTo(digitMatcher, alphabeticMatcher, token)); + assertEquals("123", token.toString()); + } +} |