blob: d39c5962ad0ac039cfd47ca0e64eb6b1388b5414 [file] [log] [blame]
Piotr Pawliczekcdd921f2020-05-06 17:35:58 -07001// Copyright 2020 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "foomatic_shell/grammar.h"
6#include "foomatic_shell/scanner.h"
7
8#include <gtest/gtest.h>
9#include <string>
10#include <vector>
11
12namespace foomatic_shell {
13
14namespace {
15
16// This function takes the input script as |input| and a sequence of tokens
17// produced by a scanner (|tokens|). It generates and returns the string
18// representation of the generated tokens. The returned string has the same
19// length as |input|. The corresponding characters are set depending on the
20// type of token covering given range according to the following rules:
21// - 'B' - Byte
22// - 'E' - ExecutedString
23// - 'I' - InterpretedString
24// - 'L' - LiteralString
25// - 'S' - Space
26// Positions that do not belong to any token are set to spaces.
27// Example:
28// - input string : abcde'rft' "dsfds"; `aaa` | bbb
29// - representation: NNNNN LLL SS IIIII BS EEE SBSNNN
30//
31// The returned representation is calculated from |tokens|, not from |input|.
32// The |input| string must be a reference to the same string as given to the
33// scanner that produced |tokens|.
34std::string CreateTokensRepresentation(const std::string& input,
35 const std::vector<Token>& tokens) {
36 std::string out(input.size(), ' ');
37 for (const Token& token : tokens) {
38 char c = 'x';
39 switch (token.type) {
40 case Token::Type::kByte:
41 c = 'B';
42 break;
43 case Token::Type::kExecutedString:
44 c = 'E';
45 break;
46 case Token::Type::kInterpretedString:
47 c = 'I';
48 break;
49 case Token::Type::kLiteralString:
50 c = 'L';
51 break;
52 case Token::Type::kNativeString:
53 c = 'N';
54 break;
55 case Token::Type::kSpace:
56 c = 'S';
57 break;
58 default:
59 break;
60 }
61 const size_t begin = token.begin - input.begin();
62 const size_t end = token.end - input.begin();
63 for (size_t i = begin; i < end; ++i)
64 out[i] = c;
65 }
66 return out;
67}
68
69TEST(Scanner, StringTypes) {
70 const std::string input = "command 'lit str' `exe str` \"int str\" nat str";
71 const std::string types = "NNNNNNNS LLLLLLL S EEEEEEE SS IIIIIII SNNNSNNN";
72 Scanner scanner(input);
73 std::vector<Token> tokens;
74 EXPECT_TRUE(scanner.ParseWholeInput(&tokens));
75 EXPECT_EQ(types, CreateTokensRepresentation(input, tokens));
76}
77
78TEST(Scanner, ExecutedStringInsideInterpretedString) {
79 const std::string input = "command \"int str1`exe str`int str2\" ";
80 const std::string types = "NNNNNNNS IIIIIIII EEEEEEE IIIIIIII SS";
81 Scanner scanner(input);
82 std::vector<Token> tokens;
83 EXPECT_TRUE(scanner.ParseWholeInput(&tokens));
84 EXPECT_EQ(types, CreateTokensRepresentation(input, tokens));
85}
86
87TEST(Scanner, UnterminatedLiteralString) {
88 const std::string input = "command 'int str1`exe str`int s";
89 Scanner scanner(input);
90 std::vector<Token> tokens;
91 EXPECT_FALSE(scanner.ParseWholeInput(&tokens));
92 EXPECT_EQ(scanner.GetPosition(), input.end());
93}
94
95TEST(Scanner, UnterminatedInterpretedString) {
96 const std::string input = "command \"int str1`exe str`int s";
97 Scanner scanner(input);
98 std::vector<Token> tokens;
99 EXPECT_FALSE(scanner.ParseWholeInput(&tokens));
100 EXPECT_EQ(scanner.GetPosition(), input.end());
101}
102
103TEST(Scanner, UnterminatedExecutedString) {
104 const std::string input = "command 'int str1' `exe str";
105 Scanner scanner(input);
106 std::vector<Token> tokens;
107 EXPECT_FALSE(scanner.ParseWholeInput(&tokens));
108 EXPECT_EQ(scanner.GetPosition(), input.end());
109}
110
111TEST(Scanner, CommandWithParameters) {
112 const std::string input =
113 "pdftops '9195' 'root' 'split_streams.pdf' '1' "
114 "' finishings=3 number-up=1 document=split.pdf' '/cups/tmp/foo-B65TL1'";
115 const std::string types =
116 "NNNNNNNS LLLL S LLLL S LLLLLLLLLLLLLLLLL S L S"
117 " LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL S LLLLLLLLLLLLLLLLLLLL ";
118 std::vector<Token> tokens;
119 Scanner scanner(input);
120 EXPECT_TRUE(scanner.ParseWholeInput(&tokens));
121 EXPECT_EQ(types, CreateTokensRepresentation(input, tokens));
122}
123
124TEST(Scanner, Pipeline) {
125 const std::string input = "ls -h | grep 'XXX' | wc -l; echo \"Done\"; ";
126 const std::string types = "NNSNNSBSNNNNS LLL SBSNNSNNBSNNNNS IIII BS";
127 std::vector<Token> tokens;
128 Scanner scanner(input);
129 EXPECT_TRUE(scanner.ParseWholeInput(&tokens));
130 EXPECT_EQ(types, CreateTokensRepresentation(input, tokens));
131}
132
133TEST(Scanner, Subshell) {
134 const std::string input =
135 "VAR1='xx' VAR=acs'zzz'qq my_app -par1 par2'qqq'"
136 " ; (echo ttt | tr t T; echo Done) | cat myfile.txt";
137 const std::string types =
138 "NNNNB LL SNNNBNNN LLL NNSSNNNNNNSSNNNNNSNNNN LLL "
139 "SBSBNNNNSNNNSBSNNSNSNBSNNNNSNNNNBSBSNNNSNNNNNNNNNN";
140 std::vector<Token> tokens;
141 Scanner scanner(input);
142 EXPECT_TRUE(scanner.ParseWholeInput(&tokens));
143 EXPECT_EQ(types, CreateTokensRepresentation(input, tokens));
144}
145
146} // namespace
147
148} // namespace foomatic_shell