blob: 9d88fe0049e8f3d71e97a1115ce80017cded67a4 [file] [log] [blame]
// Copyright 2019 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package com.google.devtools.build.lib.bazel.rules.ninja;
import static com.google.common.truth.Truth.assertThat;
import com.google.devtools.build.lib.bazel.rules.ninja.file.ByteBufferFragment;
import com.google.devtools.build.lib.bazel.rules.ninja.lexer.NinjaLexerStep;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.function.Consumer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for {@link com.google.devtools.build.lib.bazel.rules.ninja.lexer.NinjaLexerStep}. */
@RunWith(JUnit4.class)
public class NinjaLexerStepTest {
@Test
public void testSkipSpaces() {
NinjaLexerStep step = step(" ");
assertThat(step.canAdvance()).isTrue();
assertThat(step.startByte()).isEqualTo(' ');
step.skipSpaces();
assertThat(step.getEnd()).isEqualTo(2);
assertThat(step.getBytes()).isEqualTo(" ".getBytes(StandardCharsets.ISO_8859_1));
assertThat(step.canAdvance()).isFalse();
}
@Test
public void testSkipComment() {
doTest("# skfdskl werj wior982438923u rekfjg wef w $ $: : |", NinjaLexerStep::skipComment);
doTest("#", NinjaLexerStep::skipComment);
doTest("# 123\n", NinjaLexerStep::skipComment, "# 123", true);
doTest("# 123\u0000118", NinjaLexerStep::skipComment, "# 123", false);
}
@Test
public void testTrySkipEscapedNewline() {
doTest("$\n", step -> assertThat(step.trySkipEscapedNewline()).isTrue());
doTest("$\n\n", step -> assertThat(step.trySkipEscapedNewline()).isTrue(), "$\n", true);
doTest("$\r\n", step -> assertThat(step.trySkipEscapedNewline()).isTrue());
doTest("$\r\na", step -> assertThat(step.trySkipEscapedNewline()).isTrue(), "$\r\n", true);
}
@Test
public void testProcessLineFeedNewLine() {
doTest("\r\n", NinjaLexerStep::processLineFeedNewLine);
doTestError(
"\ra",
NinjaLexerStep::processLineFeedNewLine,
"\ra",
false,
"Wrong newline separators: \\r should be followed by \\n.");
}
@Test
public void testTryReadVariableInBrackets() {
doTest("${abc}", step -> assertThat(step.tryReadVariableInBrackets()).isTrue());
doTest("$abc", step -> assertThat(step.tryReadVariableInBrackets()).isFalse(), "", true);
doTest("${ abc }", step -> assertThat(step.tryReadVariableInBrackets()).isTrue());
doTest(
"${abc.xyz-1_2}cde",
step -> assertThat(step.tryReadVariableInBrackets()).isTrue(),
"${abc.xyz-1_2}",
true);
doTestError(
"${abc",
step -> assertThat(step.tryReadVariableInBrackets()).isTrue(),
"${abc",
false,
"Variable end symbol '}' expected.");
doTestError(
"${abc\n",
step -> assertThat(step.tryReadVariableInBrackets()).isTrue(),
"${abc\n",
false,
"Variable end symbol '}' expected.");
doTestError(
"${}",
step -> assertThat(step.tryReadVariableInBrackets()).isTrue(),
"${}",
false,
"Variable identifier expected.");
doTestError(
"${^}",
step -> assertThat(step.tryReadVariableInBrackets()).isTrue(),
"${^",
true,
"Variable identifier expected.");
}
@Test
public void testTryReadSimpleVariable() {
doTest("$abc", step -> assertThat(step.tryReadSimpleVariable()).isTrue());
doTest("$a-b_c", step -> assertThat(step.tryReadSimpleVariable()).isTrue());
doTest("$.", step -> assertThat(step.tryReadSimpleVariable()).isFalse(), "", true);
doTest("$abc.cde", step -> assertThat(step.tryReadSimpleVariable()).isTrue(), "$abc", true);
}
@Test
public void testTryReadEscapedLiteral() {
doTest("$:", step -> assertThat(step.tryReadEscapedLiteral()).isTrue(), "$:", false);
doTest("$$", step -> assertThat(step.tryReadEscapedLiteral()).isTrue(), "$$", false);
doTest("$ ", step -> assertThat(step.tryReadEscapedLiteral()).isTrue(), "$ ", false);
doTest("$:a", step -> assertThat(step.tryReadEscapedLiteral()).isTrue(), "$:", true);
doTest("$$$", step -> assertThat(step.tryReadEscapedLiteral()).isTrue(), "$$", true);
doTest("$ ", step -> assertThat(step.tryReadEscapedLiteral()).isTrue(), "$ ", true);
doTest("$a", step -> assertThat(step.tryReadEscapedLiteral()).isFalse(), "", true);
}
@Test
public void testTryReadIdentifier() {
doTest("abc_d-18", NinjaLexerStep::tryReadIdentifier);
doTest("abc_d-18.ccc", NinjaLexerStep::tryReadIdentifier);
doTest("abc_d-18.ccc=", NinjaLexerStep::tryReadIdentifier, "abc_d-18.ccc", true);
// Have a longer text to demonstrate the error output.
doTestError(
"^abc Bazel only rebuilds what is necessary. "
+ "With advanced local and distributed caching, optimized dependency analysis "
+ "and parallel execution, you get fast and incremental builds.",
NinjaLexerStep::tryReadIdentifier,
"^",
true,
"Symbol '^' is not allowed in the identifier, the text fragment with the symbol:\n"
+ "^abc Bazel only rebuilds what is necessary. With advanced local and distributed"
+ " caching, optimized dependency analysis and parallel execution,"
+ " you get fast and incremental builds.\n");
}
@Test
public void testTryReadDoublePipe() {
doTest("||", NinjaLexerStep::tryReadDoublePipe);
}
@Test
public void testReadText() {
doTest("text$\npart", NinjaLexerStep::readText, "text", true);
doTest("one word", NinjaLexerStep::readText, "one", true);
}
private static void doTest(String text, Consumer<NinjaLexerStep> callback) {
doTest(text, callback, text, false);
}
private static void doTest(
String text, Consumer<NinjaLexerStep> callback, String expected, boolean haveMore) {
NinjaLexerStep step = step(text);
assertThat(step.canAdvance()).isTrue();
callback.accept(step);
assertThat(step.getError()).isNull();
if (!expected.isEmpty()) {
assertThat(step.getBytes()).isEqualTo(expected.getBytes(StandardCharsets.ISO_8859_1));
}
assertThat(step.canAdvance()).isEqualTo(haveMore);
}
private static void doTestError(
String text,
Consumer<NinjaLexerStep> callback,
String expected,
boolean haveMore,
String errorText) {
NinjaLexerStep step = step(text);
assertThat(step.canAdvance()).isTrue();
callback.accept(step);
assertThat(step.getError()).isEqualTo(errorText);
assertThat(step.getBytes()).isEqualTo(expected.getBytes(StandardCharsets.ISO_8859_1));
assertThat(step.getFragment().length() > step.getEnd()).isEqualTo(haveMore);
}
private static NinjaLexerStep step(String text) {
ByteBuffer bb = ByteBuffer.wrap(text.getBytes(StandardCharsets.ISO_8859_1));
return new NinjaLexerStep(new ByteBufferFragment(bb, 0, bb.limit()), 0);
}
}