Squashed 'third_party/ctemplate/' content from commit 6742f62
Change-Id: I828e4e4c906f13ba19944d78a8a78652b62949af
git-subtree-dir: third_party/ctemplate
git-subtree-split: 6742f6233db12f545e90baa8f34f5c29c4eb396a
diff --git a/src/tests/template_test_util.cc b/src/tests/template_test_util.cc
new file mode 100644
index 0000000..57f7f91
--- /dev/null
+++ b/src/tests/template_test_util.cc
@@ -0,0 +1,309 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+
+#include "config_for_unittests.h"
+#include "base/mutex.h" // must come first, for _XOPEN_SOURCE
+#include "tests/template_test_util.h"
+#include <assert.h> // for assert()
+#ifdef HAVE_DIRENT_H
+# include <dirent.h> // for opendir() etc
+#else
+# define dirent direct
+# ifdef HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif // for DIR, dirent, closedir(), opendir(), etc
+#include <stdio.h> // for printf(), FILE, fclose(), fopen(), etc
+#include <stdlib.h> // for exit()
+#include <string.h> // for strcmp(), strcpy(), strstr()
+#include <sys/stat.h> // for mkdir()
+#include <sys/types.h> // for mode_t
+#include <time.h> // for time_t
+#ifdef HAVE_UTIME_H
+# include <utime.h>
+#endif // for utime()
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif // for unlink()
+#include <vector> // for vector<>, vector<>::size_type
+#include <ctemplate/template.h> // for Template
+#include <ctemplate/template_dictionary.h> // for TemplateDictionary
+#include <ctemplate/template_dictionary_interface.h>
+#include <ctemplate/template_enums.h> // for Strip
+#include <ctemplate/template_namelist.h> // for TemplateNamelist, etc
+#include <ctemplate/template_pathops.h> // for PathJoin()
+#include "base/util.h" // for down_cast()
+
+using std::string;
+using std::vector;
+
+#ifdef ASSERT
+# undef ASSERT
+#endif
+#define ASSERT(cond) do { \
+ if (!(cond)) { \
+ printf("ASSERT FAILED, line %d: %s\n", __LINE__, #cond); \
+ assert(cond); \
+ exit(1); \
+ } \
+} while (0)
+
+namespace ctemplate {
+
+// Deletes all files named *template* in dir, and sets up dir as the
+// place where StringToTemplate writes.
+static char* g_tmpdir = NULL;
+
+#ifndef USING_PORT_CC /* windows defines its own version in windows/port.cc */
+void CreateOrCleanTestDir(const string& dirname) {
+ DIR* dir = opendir(dirname.c_str());
+ if (!dir) { // directory doesn't exist or something like that
+ mkdir(dirname.c_str(), 0755); // make the dir if we can
+ return;
+ }
+ while (struct dirent* d = readdir(dir)) {
+ if (strstr(d->d_name, "template"))
+ unlink(PathJoin(dirname, d->d_name).c_str());
+ }
+ closedir(dir);
+}
+
+static string TmpFile(const char* basename) {
+ return string("/tmp/") + basename;
+}
+
+#endif // #ifndef USING_PORT_CC
+
+void CreateOrCleanTestDirAndSetAsTmpdir(const string& dirname) {
+ CreateOrCleanTestDir(dirname);
+ delete[] g_tmpdir;
+ g_tmpdir = new char[dirname.length() + 1];
+ strcpy(g_tmpdir, dirname.c_str());
+}
+
+const string FLAGS_test_tmpdir(TmpFile("template_unittest_dir"));
+
+// This writes s to the given file. We want to make sure that every
+// time we create a file, it has a different mtime (just like would
+// be the case in real life), so we use a mock clock.
+static Mutex g_time_mutex(base::LINKER_INITIALIZED);
+static time_t mock_time = 946713600; // jan 1, 2000, in california
+
+void StringToFile(const string& s, const string& filename) {
+ FILE* fp = fopen(filename.c_str(), "wb");
+ ASSERT(fp);
+ size_t r = fwrite(s.data(), 1, s.length(), fp);
+ ASSERT(r == s.length());
+ fclose(fp);
+
+ g_time_mutex.Lock();
+ const time_t file_time = mock_time++;
+ g_time_mutex.Unlock();
+ struct utimbuf timbuf = { file_time, file_time };
+ utime(filename.c_str(), &timbuf);
+}
+
+time_t Now() {
+ g_time_mutex.Lock();
+ const time_t now = mock_time;
+ g_time_mutex.Unlock();
+ return now;
+}
+
+// This writes s to a file and returns the filename.
+string StringToTemplateFile(const string& s) {
+ static int filenum = 0;
+ char buf[16];
+ snprintf(buf, sizeof(buf), "%03d", ++filenum);
+ string filename = PathJoin(g_tmpdir ? g_tmpdir : "",
+ string("template.") + buf);
+ StringToFile(s, filename);
+ return filename;
+}
+
+// This writes s to a file and then loads it into a template object.
+Template* StringToTemplate(const string& s, Strip strip) {
+ return Template::GetTemplate(StringToTemplateFile(s), strip);
+}
+
+// This is esp. useful for calling from within gdb.
+// The gdb nice-ness is balanced by the need for the caller to delete the buf.
+
+const char* ExpandIs(const Template* tpl, const TemplateDictionary *dict,
+ PerExpandData* per_expand_data, bool expected) {
+ string outstring;
+ if (per_expand_data)
+ ASSERT(expected == tpl->ExpandWithData(&outstring, dict, per_expand_data));
+ else
+ ASSERT(expected == tpl->Expand(&outstring, dict));
+
+
+ char* buf = new char[outstring.size()+1];
+ strcpy(buf, outstring.c_str());
+ return buf;
+}
+
+const char* ExpandWithCacheIs(TemplateCache* cache,
+ const string& filename, Strip strip,
+ const TemplateDictionary *dict,
+ PerExpandData* per_expand_data, bool expected) {
+ string outstring;
+ ASSERT(expected == cache->ExpandWithData(filename, strip, dict,
+ per_expand_data, &outstring));
+
+
+ char* buf = new char[outstring.size()+1];
+ strcpy(buf, outstring.c_str());
+ return buf;
+}
+
+void AssertExpandWithDataIs(const Template* tpl,
+ const TemplateDictionary *dict,
+ PerExpandData* per_expand_data,
+ const string& is, bool expected) {
+ const char* buf = ExpandIs(tpl, dict, per_expand_data, expected);
+ if (strcmp(buf, is.c_str())) {
+ printf("expected = '%s'\n", is.c_str());
+ printf("actual = '%s'\n", buf);
+ }
+ ASSERT(string(buf) == is);
+ delete [] buf;
+}
+
+void AssertExpandIs(const Template* tpl, const TemplateDictionary *dict,
+ const string& is, bool expected) {
+ AssertExpandWithDataIs(tpl, dict, NULL, is, expected);
+}
+
+void AssertExpandWithCacheIs(TemplateCache* cache,
+ const string& filename, Strip strip,
+ const TemplateDictionary *dict,
+ PerExpandData* per_expand_data,
+ const string& is, bool expected) {
+ const char* buf = ExpandWithCacheIs(cache, filename, strip, dict,
+ per_expand_data, expected);
+ if (strcmp(buf, is.c_str())) {
+ printf("expected = '%s'\n", is.c_str());
+ printf("actual = '%s'\n", buf);
+ }
+ ASSERT(string(buf) == is);
+ delete [] buf;
+}
+
+TemporaryRegisterTemplate::TemporaryRegisterTemplate(const char* name) {
+ old_namelist_ = TemplateNamelist::namelist_;
+ if (old_namelist_) {
+ namelist_ = *old_namelist_;
+ }
+
+ namelist_.insert(name);
+ TemplateNamelist::namelist_ = &namelist_;
+}
+
+TemporaryRegisterTemplate::~TemporaryRegisterTemplate() {
+ TemplateNamelist::namelist_ = old_namelist_;
+}
+
+const char* TemplateDictionaryPeer::GetSectionValue(
+ const TemplateString& variable)
+ const {
+ // Luckily, TemplateDictionary stores all values with a trailing NUL.
+ return dict_->GetValue(variable).data();
+}
+
+bool TemplateDictionaryPeer::ValueIs(const TemplateString& variable,
+ const TemplateString& expected) const {
+ return dict_->GetValue(variable) == expected;
+}
+
+bool TemplateDictionaryPeer::IsHiddenSection(
+ const TemplateString& name) const {
+ return dict_->IsHiddenSection(name);
+}
+
+bool TemplateDictionaryPeer::IsUnhiddenSection(
+ const TemplateString& name) const {
+ return dict_->IsUnhiddenSection(name);
+}
+
+bool TemplateDictionaryPeer::IsHiddenTemplate(
+ const TemplateString& name) const {
+ return dict_->IsHiddenTemplate(name);
+}
+
+int TemplateDictionaryPeer::GetSectionDictionaries(
+ const TemplateString& section_name,
+ vector<const TemplateDictionary*>* dicts) const {
+ dicts->clear();
+ if (dict_->IsHiddenSection(section_name))
+ return 0;
+
+ TemplateDictionaryInterface::Iterator* di =
+ dict_->CreateSectionIterator(section_name);
+ while (di->HasNext())
+ dicts->push_back(down_cast<const TemplateDictionary*>(&di->Next()));
+ delete di;
+
+ return static_cast<int>(dicts->size());
+}
+
+int TemplateDictionaryPeer::GetIncludeDictionaries(
+ const TemplateString& section_name,
+ vector<const TemplateDictionary*>* dicts) const {
+ dicts->clear();
+ if (dict_->IsHiddenTemplate(section_name))
+ return 0;
+
+ TemplateDictionaryInterface::Iterator* di =
+ dict_->CreateTemplateIterator(section_name);
+ while (di->HasNext())
+ dicts->push_back(down_cast<const TemplateDictionary*>(&di->Next()));
+ delete di;
+
+ return static_cast<int>(dicts->size());
+}
+
+const char* TemplateDictionaryPeer::GetIncludeTemplateName(
+ const TemplateString& variable, int dictnum) const {
+ return dict_->GetIncludeTemplateName(variable, dictnum);
+}
+
+const char* TemplateDictionaryPeer::GetFilename() const {
+ return dict_->filename_;
+}
+
+}