| // Copyright 2020 The Chromium OS Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "foomatic_shell/grammar.h" | |
| #include "foomatic_shell/parser.h" | |
| #include "foomatic_shell/scanner.h" | |
| #include <gtest/gtest.h> | |
| #include <string> | |
| #include <utility> | |
| #include <vector> | |
| namespace foomatic_shell { | |
| // Calls CreateRepresentation(...) for each element of the given vector and | |
| // returns single string built from the results according to the following | |
| // pattern: "[result0,result1,result2,...]" | |
| template <typename Element> | |
| std::string CreateRepresentation(const std::vector<Element>& elements) { | |
| std::string out = "["; | |
| for (size_t i = 0; i < elements.size(); ++i) { | |
| if (i > 0) | |
| out += ","; | |
| out += CreateRepresentation(elements[i]); | |
| } | |
| out.push_back(']'); | |
| return out; | |
| } | |
| // A string representation of StringAtom is its value. | |
| std::string CreateRepresentation(const StringAtom& str) { | |
| std::string out; | |
| for (auto& s : str.components) { | |
| if (s.type == Token::Type::kLiteralString) | |
| out += std::string(s.begin, s.end); | |
| else | |
| out += s.value; | |
| } | |
| return out; | |
| } | |
| // A string representation of variable assignment is a name of variable and | |
| // a value of the variable connected by '=' character. | |
| std::string CreateRepresentation(const VariableAssignment& variable) { | |
| std::string out; | |
| out = variable.variable.value; | |
| out += "="; | |
| out += CreateRepresentation(variable.new_value); | |
| return out; | |
| } | |
| std::string CreateRepresentation(const Script& script); | |
| // This function returns a string representation of given PipeSegment. | |
| // If the PipeSegment is a Command, its string representation is calculated | |
| // according to the following pattern: | |
| // "{[var0=value0,var1=value1,...],application,[param0,param1,...]}" | |
| std::string CreateRepresentation(const PipeSegment& segment) { | |
| std::string out; | |
| if (segment.command) { | |
| out += "{"; | |
| out += CreateRepresentation(segment.command->variables_with_values); | |
| out += ","; | |
| out += segment.command->application.value; | |
| out += ","; | |
| out += CreateRepresentation(segment.command->parameters); | |
| out += "}"; | |
| } else { | |
| return CreateRepresentation(*segment.script); | |
| } | |
| return out; | |
| } | |
| // This function returns a string representation of given Pipeline as a | |
| // sequence of string representations of its segments. | |
| std::string CreateRepresentation(const Pipeline& pipeline) { | |
| return CreateRepresentation(pipeline.segments); | |
| } | |
| // This function returns a string representation of given Script as a | |
| // sequence of string representations of its pipelines. | |
| std::string CreateRepresentation(const Script& script) { | |
| return CreateRepresentation(script.pipelines); | |
| } | |
| TEST(Parser, CommandWithParameters) { | |
| const std::string input = | |
| "pdftops '9195' 'root' 'split_streams.pdf' '1' " | |
| "' finishings=3 number-up=1 document=split.pdf' '/cups/tmp/foo-B65TL1'"; | |
| const std::string tree = | |
| "[[{[],pdftops,[9195,root,split_streams.pdf,1," | |
| " finishings=3 number-up=1 document=split.pdf,/cups/tmp/foo-B65TL1]}]]"; | |
| std::vector<Token> tokens; | |
| Scanner scanner(input); | |
| ASSERT_TRUE(scanner.ParseWholeInput(&tokens)); | |
| Parser parser(std::move(tokens)); | |
| Script script; | |
| EXPECT_TRUE(parser.ParseWholeInput(&script)); | |
| EXPECT_EQ(tree, CreateRepresentation(script)); | |
| } | |
| TEST(Parser, Pipeline) { | |
| const std::string input = "ls -h | grep 'XXX' | wc -l; echo \"Done\"; "; | |
| const std::string tree = | |
| "[[{[],ls,[-h]},{[],grep,[XXX]},{[],wc,[-l]}]," | |
| "[{[],echo,[Done]}]]"; | |
| std::vector<Token> tokens; | |
| Scanner scanner(input); | |
| ASSERT_TRUE(scanner.ParseWholeInput(&tokens)); | |
| Parser parser(std::move(tokens)); | |
| Script script; | |
| EXPECT_TRUE(parser.ParseWholeInput(&script)); | |
| EXPECT_EQ(tree, CreateRepresentation(script)); | |
| } | |
| TEST(Parser, Subshell) { | |
| const std::string input = | |
| "VAR1='xx' VAR=acs'zzz'qq my_app -par1 par2'qqq'" | |
| " ; (echo ttt | tr t T; echo Done) | cat myfile.txt"; | |
| const std::string tree = | |
| "[[{[VAR1=xx,VAR=acszzzqq],my_app,[-par1,par2qqq]}]," | |
| "[[[{[],echo,[ttt]},{[],tr,[t,T]}],[{[],echo,[Done]}]]," | |
| "{[],cat,[myfile.txt]}]]"; | |
| std::vector<Token> tokens; | |
| Scanner scanner(input); | |
| ASSERT_TRUE(scanner.ParseWholeInput(&tokens)); | |
| Parser parser(std::move(tokens)); | |
| Script script; | |
| EXPECT_TRUE(parser.ParseWholeInput(&script)); | |
| EXPECT_EQ(tree, CreateRepresentation(script)); | |
| } | |
| } // namespace foomatic_shell |