| // 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); |
| } |
| } |