public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-commits] proj/libbash:master commit in: scripts/, /, src/core/, bashast/, src/core/tests/
@ 2011-05-22 21:00 Petteri Räty
  0 siblings, 0 replies; only message in thread
From: Petteri Räty @ 2011-05-22 21:00 UTC (permalink / raw
  To: gentoo-commits

commit:     48d8c264bcf995c6c8450a710debbb3e5e6901f0
Author:     Mu Qiao <qiaomuf <AT> gentoo <DOT> org>
AuthorDate: Tue May 17 10:10:42 2011 +0000
Commit:     Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
CommitDate: Sun May 22 16:16:34 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/libbash.git;a=commit;h=48d8c264

Walker: support file stat test

---
 Makefile.am                            |    3 +
 bashast/libbashWalker.g                |    6 +-
 scripts/test_expr.bash                 |    1 +
 scripts/test_expr.bash.result          |    1 +
 src/core/bash_condition.cpp            |  115 ++++++++++++++++++++++++++
 src/core/bash_condition.h              |   34 ++++++++
 src/core/tests/bash_condition_test.cpp |  139 ++++++++++++++++++++++++++++++++
 7 files changed, 298 insertions(+), 1 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 5b33379..b680cd0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -97,6 +97,7 @@ cppunittests_SOURCES =  test/run_tests.cpp \
 						src/core/tests/symbols_test.cpp \
 						src/core/tests/interpreter_test.cpp \
 						src/core/tests/bash_ast_test.cpp \
+						src/core/tests/bash_condition_test.cpp \
 						src/builtins/tests/echo_tests.cpp \
 						src/builtins/tests/boolean_tests.cpp \
 						src/builtins/tests/source_tests.cpp \
@@ -187,6 +188,8 @@ libcppbash_la_SOURCES = src/common.h \
 						src/core/interpreter.cpp \
 						src/core/interpreter.h \
 						src/core/symbols.hpp \
+						src/core/bash_condition.h \
+						src/core/bash_condition.cpp \
 						src/core/bash_ast.cpp \
 						src/core/bash_ast.h
 

diff --git a/bashast/libbashWalker.g b/bashast/libbashWalker.g
index a341109..737c7a7 100644
--- a/bashast/libbashWalker.g
+++ b/bashast/libbashWalker.g
@@ -46,6 +46,7 @@ options
 	#include <boost/format.hpp>
 
 	#include "builtins/builtin_exceptions.h"
+	#include "core/bash_condition.h"
 	#include "core/interpreter.h"
 	#include "cppbash_builtin.h"
 
@@ -510,7 +511,10 @@ common_condition returns[bool status]
 	// -eq, -ne, -lt, -le, -gt, or -ge for arithmetic. -nt -ot -ef for files
 	:^(NAME left_str=string_expr right_str=string_expr)
 	// -o for shell option,  -z -n for string, -abcdefghkprstuwxOGLSN for files
-	|^(LETTER string_expr)
+	|^(op=LETTER string_expr) {
+		$status = internal::test_unary(*reinterpret_cast<const char *>(op->getToken(op)->start),
+		                               $string_expr.libbash_value);
+	}
 	// We do not trigger pattern matching for now
 	|^((EQUALS|MATCH_PATTERN) left_str=string_expr right_str=string_expr) {
 		$status = left_str.libbash_value == right_str.libbash_value;

diff --git a/scripts/test_expr.bash b/scripts/test_expr.bash
index 1c63998..91c24fd 100644
--- a/scripts/test_expr.bash
+++ b/scripts/test_expr.bash
@@ -35,3 +35,4 @@ echo $? # 0
 [[ abc = bcd && abc == abc ]] || echo true9
 # abc=bcd is treated as a simple string
 [[ abc=bcd && abc == abc ]] || echo wrong
+[[ -a "/" ]] && echo "true10"

diff --git a/scripts/test_expr.bash.result b/scripts/test_expr.bash.result
index 63aaa92..4be03db 100644
--- a/scripts/test_expr.bash.result
+++ b/scripts/test_expr.bash.result
@@ -16,3 +16,4 @@ true6
 true7
 true8
 true9
+true10

diff --git a/src/core/bash_condition.cpp b/src/core/bash_condition.cpp
new file mode 100644
index 0000000..61a5826
--- /dev/null
+++ b/src/core/bash_condition.cpp
@@ -0,0 +1,115 @@
+/*
+   Please use git log for copyright holder and year information
+
+   This file is part of libbash.
+
+   libbash 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 2 of the License, or
+   (at your option) any later version.
+
+   libbash 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 libbash.  If not, see <http://www.gnu.org/licenses/>.
+   */
+///
+/// \file bash_condition.cpp
+/// \author Mu Qiao
+/// \brief implementation for Bash Conditional Expressions
+///
+#include <ctime>
+
+#include <boost/lexical_cast.hpp>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "core/interpreter_exception.h"
+
+#include "core/bash_condition.h"
+
+namespace
+{
+  bool test_file_stat(char op, const std::string& path)
+  {
+    struct stat info;
+    int status = 0;
+
+    // symbol link use lstat so we need to separate this.
+    if(op == 'L' || op == 'h')
+      return lstat(path.c_str(), &info) == 0 && S_ISLNK(info.st_mode);
+
+    status = stat(path.c_str(), &info);
+    if(status != 0 || access(path.c_str(), F_OK))
+      return false;
+
+    switch(op)
+    {
+      case 'a':
+      case 'e':
+        return true;
+      case 'b':
+        return S_ISBLK(info.st_mode);
+      case 'c':
+        return S_ISCHR(info.st_mode);
+      case 'd':
+        return S_ISDIR(info.st_mode);
+      case 'f':
+        return S_ISREG(info.st_mode);
+      case 'g':
+        return S_ISGID & info.st_mode;
+      case 'k':
+        return S_ISVTX & info.st_mode;
+      case 'p':
+        return S_ISFIFO(info.st_mode);
+      case 'r':
+        return access(path.c_str(), R_OK) == 0;
+      case 's':
+        return info.st_size > 0;
+      case 'u':
+        return S_ISUID & info.st_mode;
+      case 'w':
+        return access(path.c_str(), W_OK) == 0;
+      case 'x':
+        return access(path.c_str(), X_OK) == 0;
+      case 'O':
+        return geteuid() == info.st_uid;
+      case 'G':
+        return getegid() == info.st_gid;
+      case 'S':
+        return S_ISSOCK(info.st_mode);
+      case 'N':
+        return info.st_mtime >= info.st_atime;
+      default:
+        throw interpreter_exception(std::string("Unrecognized test operator -") + op);
+    }
+  }
+}
+
+bool internal::test_unary(char op, const std::string& target)
+{
+  switch(op)
+  {
+    case 'z':
+      return target.empty();
+    case 'n':
+      return !target.empty();
+    case 'o':
+      throw interpreter_exception("Shell option test is not supported");
+    case 't':
+      try
+      {
+        int fd = boost::lexical_cast<int>(target);
+        return isatty(fd);
+      }
+      catch(boost::bad_lexical_cast& e)
+      {
+        return false;
+      }
+    default:
+      return test_file_stat(op, target);
+  }
+}

diff --git a/src/core/bash_condition.h b/src/core/bash_condition.h
new file mode 100644
index 0000000..4e9cfa3
--- /dev/null
+++ b/src/core/bash_condition.h
@@ -0,0 +1,34 @@
+/*
+   Please use git log for copyright holder and year information
+
+   This file is part of libbash.
+
+   libbash 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 2 of the License, or
+   (at your option) any later version.
+
+   libbash 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 libbash.  If not, see <http://www.gnu.org/licenses/>.
+   */
+///
+/// \file bash_condition.h
+/// \author Mu Qiao
+/// \brief implementation for Bash Conditional Expressions
+///
+#ifndef LIBBASH_CORE_BASH_CONDITION_H_
+#define LIBBASH_CORE_BASH_CONDITION_H_
+
+#include <string>
+
+namespace internal
+{
+  bool test_unary(char op, const std::string& target);
+}
+
+#endif

diff --git a/src/core/tests/bash_condition_test.cpp b/src/core/tests/bash_condition_test.cpp
new file mode 100644
index 0000000..8bcf4b3
--- /dev/null
+++ b/src/core/tests/bash_condition_test.cpp
@@ -0,0 +1,139 @@
+/*
+   Please use git log for copyright holder and year information
+
+   This file is part of libbash.
+
+   libbash 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 2 of the License, or
+   (at your option) any later version.
+
+   libbash 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 libbash.  If not, see <http://www.gnu.org/licenses/>.
+*/
+///
+/// \file bash_condition_test.cpp
+/// \author Mu Qiao
+/// \brief series of unit tests for interpreter.
+///
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <utime.h>
+
+#include <boost/lexical_cast.hpp>
+#include <gtest/gtest.h>
+
+#include "core/bash_condition.h"
+#include "core/interpreter_exception.h"
+
+namespace
+{
+  void set_time(const std::string& target, int ac, int mod)
+  {
+    struct utimbuf timebuf;
+    timebuf.actime = ac;
+    timebuf.modtime = mod;
+    EXPECT_EQ(0, utime(target.c_str(), &timebuf));
+  }
+
+  class file_test: public testing::Test
+  {
+    protected:
+      const std::string positive;
+      const std::string negative;
+      const std::string test_link;
+      const std::string test_fifo;
+
+      file_test(): positive("scripts/test.positive"),
+                   negative("scripts/test.negative"),
+                   test_link("scripts/test.link"),
+                   test_fifo("scripts/test.fifo") {}
+
+      virtual void SetUp()
+      {
+        EXPECT_NE(-1, creat(positive.c_str(),
+                            S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
+                 ) << "Can't create " << positive << " for test";
+        set_time(positive, 0, 0);
+        EXPECT_NE(-1, creat(negative.c_str(), 0)) << "Can't create " << negative << " for test";
+        set_time(negative, 1, 0);
+        EXPECT_EQ(0, symlink(positive.c_str(), test_link.c_str()));
+        EXPECT_EQ(0, mkfifo(test_fifo.c_str(), 0));
+      }
+
+      virtual void TearDown()
+      {
+        EXPECT_EQ(0, unlink(test_fifo.c_str()));
+        EXPECT_EQ(0, unlink(positive.c_str()));
+        EXPECT_EQ(0, unlink(negative.c_str()));
+        EXPECT_EQ(0, unlink(test_link.c_str()));
+      }
+  };
+}
+
+TEST_F(file_test, file_flags_positive)
+{
+  EXPECT_TRUE(internal::test_unary('a', "/"));
+  EXPECT_TRUE(internal::test_unary('b', "/dev/root")) << "You should have /dev/root, or unit test won't pass";
+  EXPECT_TRUE(internal::test_unary('c', "/dev/random"));
+  EXPECT_TRUE(internal::test_unary('d', "/"));
+  EXPECT_TRUE(internal::test_unary('e', "/"));
+  EXPECT_TRUE(internal::test_unary('f', positive));
+  EXPECT_TRUE(internal::test_unary('g', positive));
+  EXPECT_TRUE(internal::test_unary('h', test_link));
+  EXPECT_TRUE(internal::test_unary('k', positive));
+  EXPECT_TRUE(internal::test_unary('p', test_fifo));
+  EXPECT_TRUE(internal::test_unary('r', positive));
+  EXPECT_TRUE(internal::test_unary('s', "/etc/fstab"));
+  EXPECT_TRUE(internal::test_unary('u', positive));
+  EXPECT_TRUE(internal::test_unary('w', positive));
+  EXPECT_TRUE(internal::test_unary('x', positive));
+  EXPECT_TRUE(internal::test_unary('L', test_link));
+  EXPECT_TRUE(internal::test_unary('O', positive));
+  EXPECT_TRUE(internal::test_unary('G', positive));
+  EXPECT_TRUE(internal::test_unary('S', "/dev/log")) << "You should have /dev/log, or unit test won't pass";
+  EXPECT_TRUE(internal::test_unary('N', positive));
+}
+
+TEST_F(file_test, file_flags_negative)
+{
+  EXPECT_FALSE(internal::test_unary('a', "not_exist"));
+  EXPECT_FALSE(internal::test_unary('b', negative));
+  EXPECT_FALSE(internal::test_unary('c', negative));
+  EXPECT_FALSE(internal::test_unary('d', negative));
+  EXPECT_FALSE(internal::test_unary('e', "not_exist"));
+  EXPECT_FALSE(internal::test_unary('f', "/"));
+  EXPECT_FALSE(internal::test_unary('g', negative));
+  EXPECT_FALSE(internal::test_unary('h', negative));
+  EXPECT_FALSE(internal::test_unary('k', negative));
+  EXPECT_FALSE(internal::test_unary('p', negative));
+  EXPECT_FALSE(internal::test_unary('r', negative));
+  EXPECT_FALSE(internal::test_unary('s', negative));
+  EXPECT_FALSE(internal::test_unary('t', "/dev/stdin"));
+  EXPECT_FALSE(internal::test_unary('u', negative));
+  EXPECT_FALSE(internal::test_unary('w', negative));
+  EXPECT_FALSE(internal::test_unary('x', negative));
+  EXPECT_FALSE(internal::test_unary('L', negative));
+  EXPECT_FALSE(internal::test_unary('O', "/etc/fstab"));
+  EXPECT_FALSE(internal::test_unary('G', "/etc/fstab"));
+  EXPECT_FALSE(internal::test_unary('S', negative));
+  EXPECT_FALSE(internal::test_unary('N', negative));
+}
+
+TEST(bash_condition, string_unary_operator)
+{
+  EXPECT_TRUE(internal::test_unary('z', ""));
+  EXPECT_FALSE(internal::test_unary('z', "hello"));
+
+  EXPECT_FALSE(internal::test_unary('n', ""));
+  EXPECT_TRUE(internal::test_unary('n', "hello"));
+
+  EXPECT_THROW(internal::test_unary('o', "extglob"), interpreter_exception);
+}



^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2011-05-22 21:00 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-05-22 21:00 [gentoo-commits] proj/libbash:master commit in: scripts/, /, src/core/, bashast/, src/core/tests/ Petteri Räty

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox