Fix folly/test:singleton_test - Singleton.SharedPtrUsage
[folly.git] / folly / test / FormatTest.cpp
index 5ad38ef6e0a29f314ef41ac3c2fe56e04cb07a94..5a342226fbe678b7ee32cda005af041e9b1a94ca 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 #include <folly/Format.h>
 
-#include <glog/logging.h>
-#include <gflags/gflags.h>
-#include <gtest/gtest.h>
-
-#include <folly/FBVector.h>
-#include <folly/FileUtil.h>
-#include <folly/dynamic.h>
-#include <folly/json.h>
+#include <folly/portability/GTest.h>
 
 #include <string>
 
@@ -36,7 +29,8 @@ void compareOctal(Uint u) {
   char* p = buf1 + detail::uintToOctal(buf1, detail::kMaxOctalLength, u);
 
   char buf2[detail::kMaxOctalLength + 1];
-  sprintf(buf2, "%jo", static_cast<uintmax_t>(u));
+  EXPECT_LT(snprintf(buf2, sizeof(buf2), "%jo", static_cast<uintmax_t>(u)),
+            sizeof(buf2));
 
   EXPECT_EQ(std::string(buf2), std::string(p));
 }
@@ -48,7 +42,8 @@ void compareHex(Uint u) {
   char* p = buf1 + detail::uintToHexLower(buf1, detail::kMaxHexLength, u);
 
   char buf2[detail::kMaxHexLength + 1];
-  sprintf(buf2, "%jx", static_cast<uintmax_t>(u));
+  EXPECT_LT(snprintf(buf2, sizeof(buf2), "%jx", static_cast<uintmax_t>(u)),
+            sizeof(buf2));
 
   EXPECT_EQ(std::string(buf2), std::string(p));
 }
@@ -109,6 +104,13 @@ TEST(Format, Simple) {
   EXPECT_EQ("hello  ", sformat("{:<7}", "hello"));
   EXPECT_EQ("  hello", sformat("{:>7}", "hello"));
 
+  EXPECT_EQ("  hi", sformat("{:>*}", 4, "hi"));
+  EXPECT_EQ("   hi!", sformat("{:*}{}", 3, "", "hi!"));
+  EXPECT_EQ("    123", sformat("{:*}", 7, 123));
+  EXPECT_EQ("123    ", sformat("{:<*}", 7, 123));
+  EXPECT_EQ("----<=>----", sformat("{:-^*}", 11, "<=>"));
+  EXPECT_EQ("+++456+++", sformat("{2:+^*0}", 9, "unused", 456));
+
   std::vector<int> v1 {10, 20, 30};
   EXPECT_EQ("0020", sformat("{0[1]:04}", v1));
   EXPECT_EQ("0020", svformat("{1:04}", v1));
@@ -124,20 +126,22 @@ TEST(Format, Simple) {
   EXPECT_EQ("0042", sformat("{0[3]:04}", defaulted(v2, 42)));
   EXPECT_EQ("0042", svformat("{3:04}", defaulted(v2, 42)));
 
-  const int p[] = {10, 20, 30};
-  const int* q = p;
-  EXPECT_EQ("0020", sformat("{0[1]:04}", p));
-  EXPECT_EQ("0020", svformat("{1:04}", p));
-  EXPECT_EQ("0020", sformat("{0[1]:04}", q));
-  EXPECT_EQ("0020", svformat("{1:04}", q));
-  EXPECT_NE("", sformat("{}", q));
-
-  EXPECT_EQ("0x", sformat("{}", p).substr(0, 2));
-  EXPECT_EQ("10", svformat("{}", p));
-  EXPECT_EQ("0x", sformat("{}", q).substr(0, 2));
-  EXPECT_EQ("10", svformat("{}", q));
-  q = nullptr;
-  EXPECT_EQ("(null)", sformat("{}", q));
+  {
+    const int p[] = { 10, 20, 30 };
+    const int* q = p;
+    EXPECT_EQ("0020", sformat("{0[1]:04}", p));
+    EXPECT_EQ("0020", svformat("{1:04}", p));
+    EXPECT_EQ("0020", sformat("{0[1]:04}", q));
+    EXPECT_EQ("0020", svformat("{1:04}", q));
+    EXPECT_NE("", sformat("{}", q));
+
+    EXPECT_EQ("0x", sformat("{}", p).substr(0, 2));
+    EXPECT_EQ("10", svformat("{}", p));
+    EXPECT_EQ("0x", sformat("{}", q).substr(0, 2));
+    EXPECT_EQ("10", svformat("{}", q));
+    q = nullptr;
+    EXPECT_EQ("(null)", sformat("{}", q));
+  }
 
   std::map<int, std::string> m { {10, "hello"}, {20, "world"} };
   EXPECT_EQ("worldXX", sformat("{[20]:X<7}", m));
@@ -195,30 +199,9 @@ TEST(Format, Simple) {
   format(&s, "{} {}", 42, 23);
   format(&s, " hello {:X<7}", "world");
   EXPECT_EQ("42 23 hello worldXX", s);
-
-  // Test writing to FILE. I'd use open_memstream but that's not available
-  // outside of Linux (even though it's in POSIX.1-2008).
-  {
-    int fds[2];
-    CHECK_ERR(pipe(fds));
-    SCOPE_EXIT { closeNoInt(fds[1]); };
-    {
-      FILE* fp = fdopen(fds[1], "wb");
-      PCHECK(fp);
-      SCOPE_EXIT { fclose(fp); };
-      writeTo(fp, format("{} {}", 42, 23));  // <= 512 bytes (PIPE_BUF)
-    }
-
-    char buf[512];
-    ssize_t n = readFull(fds[0], buf, sizeof(buf));
-    CHECK_GE(n, 0);
-
-    EXPECT_EQ("42 23", std::string(buf, n));
-  }
 }
 
 TEST(Format, Float) {
-  double d = 1;
   EXPECT_EQ("1", sformat("{}", 1.0));
   EXPECT_EQ("0.1", sformat("{}", 0.1));
   EXPECT_EQ("0.01", sformat("{}", 0.01));
@@ -259,34 +242,6 @@ TEST(Format, MultiLevel) {
   EXPECT_EQ("world", sformat("{[0.hello]}", v));
 }
 
-TEST(Format, dynamic) {
-  auto dyn = parseJson(
-      "{\n"
-      "  \"hello\": \"world\",\n"
-      "  \"x\": [20, 30],\n"
-      "  \"y\": {\"a\" : 42}\n"
-      "}");
-
-  EXPECT_EQ("world", sformat("{0[hello]}", dyn));
-  EXPECT_THROW(sformat("{0[none]}", dyn), std::out_of_range);
-  EXPECT_EQ("world", sformat("{0[hello]}", defaulted(dyn, "meow")));
-  EXPECT_EQ("meow", sformat("{0[none]}", defaulted(dyn, "meow")));
-
-  EXPECT_EQ("20", sformat("{0[x.0]}", dyn));
-  EXPECT_THROW(sformat("{0[x.2]}", dyn), std::out_of_range);
-
-  // No support for "deep" defaulting (dyn["x"] is not defaulted)
-  auto v = dyn.at("x");
-  EXPECT_EQ("20", sformat("{0[0]}", v));
-  EXPECT_THROW(sformat("{0[2]}", v), std::out_of_range);
-  EXPECT_EQ("20", sformat("{0[0]}", defaulted(v, 42)));
-  EXPECT_EQ("42", sformat("{0[2]}", defaulted(v, 42)));
-
-  EXPECT_EQ("42", sformat("{0[y.a]}", dyn));
-
-  EXPECT_EQ("(null)", sformat("{}", dynamic(nullptr)));
-}
-
 TEST(Format, separatorDecimalInteger) {
   EXPECT_EQ("0", sformat("{:,d}", 0));
   EXPECT_EQ("1", sformat("{:d}", 1));
@@ -350,8 +305,8 @@ TEST(Format, separatorNumber) {
 // insertThousandsGroupingUnsafe requires non-const params
 static void testGrouping(const char* a_str, const char* expected) {
   char str[256];
-  strcpy(str, a_str);
-  char * end_ptr = str + strlen(str);
+  char* end_ptr = str + snprintf(str, sizeof(str), "%s", a_str);
+  ASSERT_LT(end_ptr, str + sizeof(str));
   folly::detail::insertThousandsGroupingUnsafe(str, &end_ptr);
   ASSERT_STREQ(expected, str);
 }
@@ -472,7 +427,6 @@ TEST(Format, OutOfBounds) {
 }
 
 TEST(Format, BogusFormatString) {
-  // format() will crash the program if the format string is invalid.
   EXPECT_FORMAT_ERROR(sformat("}"), "single '}' in format string");
   EXPECT_FORMAT_ERROR(sformat("foo}bar"), "single '}' in format string");
   EXPECT_FORMAT_ERROR(sformat("foo{bar"), "missing ending '}'");
@@ -481,11 +435,26 @@ TEST(Format, BogusFormatString) {
   EXPECT_FORMAT_ERROR(sformat("{1.3}", 0, 1, 2), "index not allowed");
   EXPECT_FORMAT_ERROR(sformat("{0} {} {1}", 0, 1, 2),
                "may not have both default and explicit arg indexes");
+  EXPECT_FORMAT_ERROR(sformat("{:*}", 1.2),
+                      "dynamic field width argument must be integral");
+  EXPECT_FORMAT_ERROR(sformat("{} {:*}", "hi"),
+                      "argument index out of range, max=1");
+  EXPECT_FORMAT_ERROR(
+    sformat("{:*0}", 12, "ok"),
+    "cannot provide width arg index without value arg index"
+  );
+  EXPECT_FORMAT_ERROR(
+    sformat("{0:*}", 12, "ok"),
+    "cannot provide value arg index without width arg index"
+  );
+
+  std::vector<int> v{1, 2, 3};
+  EXPECT_FORMAT_ERROR(svformat("{:*}", v),
+                      "dynamic field width not supported in vformat()");
 
   // This one fails in detail::enforceWhitespace(), which throws
   // std::range_error
-  EXPECT_THROW_STR(sformat("{0[test}"), std::range_error,
-                   "Non-whitespace: [");
+  EXPECT_THROW_STR(sformat("{0[test}"), std::range_error, "Non-whitespace");
 }
 
 template <bool containerMode, class... Args>
@@ -539,9 +508,3 @@ TEST(Format, Extending) {
                        "another formatter"),
             "Extending {a {formatter}} in {another formatter}");
 }
-
-int main(int argc, char *argv[]) {
-  testing::InitGoogleTest(&argc, argv);
-  gflags::ParseCommandLineFlags(&argc, &argv, true);
-  return RUN_ALL_TESTS();
-}