/**
* Copyright (C) 2015 drrb
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program 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 General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.drrb.rust.netbeans.rustbridge;
import com.github.drrb.rust.netbeans.parsing.RustTokenId;
import org.junit.Test;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import static com.github.drrb.rust.netbeans.parsing.RustTokenId.*;
import static org.junit.Assert.*;
import org.junit.After;
public class RustLexerTest {
private RustLexer lexer;
@After
public void cleanUpLexer() {
lexer.release();
}
@Test
public void shouldTokenizeWhitespace() {
String input = " \t ";
lexer = RustLexer.forString(input);
assertThat(lexer.nextToken(), isToken(WHITESPACE).from(1, 0).to(1, 5));
assertThat(lexer.nextToken(), isToken(EOF).from(1, 0).to(1, 5));
}
@Test
public void shouldCopeWithBadSource() throws Exception {
lexer = RustLexer.forString("fn main() å\n");
exhaustLexer();
}
@Test
public void shouldCopeWithEmptyString() throws Exception {
lexer = RustLexer.forString("");
exhaustLexer();
}
@Test
public void shouldTokenizeRustString() throws Exception {
StringBuilder source = new StringBuilder();
source.append("fn main() {\n");
source.append(" println!(\"hi!\");\n");
source.append("}\n");
source.append("\n");
lexer = RustLexer.forString(source.toString());
assertThat(lexer.nextToken(), isToken(FN).from(1, 0).to(1, 2));
assertThat(lexer.nextToken(), isToken(WHITESPACE).from(1, 2).to(1, 3));
assertThat(lexer.nextToken(), isToken(IDENT).from(1, 3).to(1, 7));
assertThat(lexer.nextToken(), isToken(OPEN_PAREN).from(1, 7).to(1, 8));
assertThat(lexer.nextToken(), isToken(CLOSE_PAREN).from(1, 8).to(1, 9));
assertThat(lexer.nextToken(), isToken(WHITESPACE).from(1, 9).to(1, 10));
assertThat(lexer.nextToken(), isToken(OPEN_BRACE).from(1, 10).to(1, 11));
assertThat(lexer.nextToken(), isToken(WHITESPACE).from(1, 11).to(2, 2));
assertThat(lexer.nextToken(), isToken(IDENT).from(2, 2).to(2, 9));
assertThat(lexer.nextToken(), isToken(NOT).from(2, 9).to(2, 10));
assertThat(lexer.nextToken(), isToken(OPEN_PAREN).from(2, 10).to(2, 11));
assertThat(lexer.nextToken(), isToken(STR_LITERAL).from(2, 11).to(2, 16));
assertThat(lexer.nextToken(), isToken(CLOSE_PAREN).from(2, 16).to(2, 17));
assertThat(lexer.nextToken(), isToken(SEMI).from(2, 17).to(2, 18));
assertThat(lexer.nextToken(), isToken(WHITESPACE).from(2, 18).to(3, 0));
assertThat(lexer.nextToken(), isToken(CLOSE_BRACE).from(3, 0).to(3, 1));
assertThat(lexer.nextToken(), isToken(WHITESPACE).from(3, 1).to(4, 1));
assertThat(lexer.nextToken(), isToken(EOF).from(3, 1).to(4, 1));
}
private void exhaustLexer() {
while (!lexer.nextToken().isEof()) { }
}
private static RustTokenMatcher.Builder isToken(RustTokenId type) {
return new RustTokenMatcher.Builder(type);
}
private static class RustTokenMatcher extends TypeSafeMatcher<RustToken> {
static class Builder {
private final RustTokenId type;
private int startLine;
private int startCol;
public Builder(RustTokenId type) {
this.type = type;
}
public Builder from(int startLine, int startCol) {
this.startLine = startLine;
this.startCol = startCol;
return this;
}
public RustTokenMatcher to(int endLine, int endCol) {
return new RustTokenMatcher(type, startLine, startCol, endLine, endCol);
}
}
private final RustTokenId type;
private final int startLine;
private final int startCol;
private final int endLine;
private final int endCol;
public RustTokenMatcher(RustTokenId type, int startLine, int startCol, int endLine, int endCol) {
this.type = type;
this.startLine = startLine;
this.startCol = startCol;
this.endLine = endLine;
this.endCol = endCol;
}
@Override
public boolean matchesSafely(RustToken item) {
return item.getType() == type
&& item.startLine == startLine
&& item.startCol == startCol
&& item.endLine == endLine
&& item.endCol == endCol;
}
@Override
public void describeTo(Description description) {
description.appendText("RustToken of type ")
.appendValue(type)
.appendText(String.format(" at %s,%s - %s,%s", startLine, startCol, endLine, endCol));
}
}
}