Parse all json's values 20/237520/8
authorIlho Kim <ilho159.kim@samsung.com>
Wed, 1 Jul 2020 01:20:53 +0000 (10:20 +0900)
committerIlho Kim <ilho159.kim@samsung.com>
Fri, 3 Jul 2020 07:21:01 +0000 (16:21 +0900)
{
  "A" : {
    "A" : "a",
    "B" : [
      "a",
      "b",
      "c"
    ],
    "C" : [
      {
        "D" : "d"
      },
      {
        "E" : "e"
      }
    ]
  }
}

Above json file is parsed and saved to bundle like that
Key Value
"A/A" "a"
"A/B" {"a", "b", "c"}
"A/C/0/D"       "d"
"A/C/1/E"       "e"

Change-Id: Ica907252ba3397898b1e22a9ec8afbe92b81cf05
Signed-off-by: Ilho Kim <ilho159.kim@samsung.com>
src/theme_plugin/theme_parser.cc
src/theme_plugin/theme_parser.h
test/unit_tests/test_samples/test_different_array_element_type.json [new file with mode: 0644]
test/unit_tests/test_samples/test_empty_array.json [new file with mode: 0644]
test/unit_tests/test_samples/test_invalid_json.json [new file with mode: 0644]
test/unit_tests/test_samples/test_multidimensional_array.json [new file with mode: 0644]
test/unit_tests/test_samples/test_theme.json
test/unit_tests/test_theme_parser.cc

index 5ecd2bc..c7f6f3b 100644 (file)
@@ -4,12 +4,12 @@
 
 #include "theme_plugin/theme_parser.h"
 
-#include <json/json.h>
 #include <sys/types.h>
 
 #include <fstream>
 #include <streambuf>
 #include <string>
+#include <vector>
 
 #include "theme/dbus/request_broker.h"
 #include "theme/loader/theme_info.h"
 namespace ttm {
 namespace plugin {
 
+bool ThemeParser::ExtractArray(const Json::Value& node,
+    std::string parent_key, ThemeInfoBuilder* builder) {
+  Json::ValueType element_type = node.begin()->type();
+  std::vector<std::string> array_values;
+  int ind = 0;
+  for (auto it = node.begin(); it != node.end(); ++it) {
+    std::string key = parent_key + "/" + std::to_string(ind++);
+    if (it->type() != element_type) {
+      LOG(ERROR) << "Json array element's type should be same";
+      return false;
+    }
+
+    if (it->isObject()) {
+      if (!ExtractJson(*it, key, builder))
+        return false;
+    } else if (it->isArray()) {
+      if (!ExtractArray(*it, key, builder))
+        return false;
+    } else {
+      array_values.emplace_back(it->asString());
+    }
+  }
+
+  if (element_type == Json::ValueType::arrayValue ||
+      element_type == Json::ValueType::objectValue)
+    return true;
+
+  if (array_values.empty()) {
+    LOG(ERROR) << "Empty array is not allowed";
+    return false;
+  }
+
+  builder->PutStringArray(parent_key, array_values);
+  return true;
+}
+
+bool ThemeParser::ExtractElement(const Json::Value &node,
+    const std::string parent_key, ThemeInfoBuilder* builder) {
+  builder->PutString(parent_key, node.asString());
+  return true;
+}
+
+bool ThemeParser::ExtractJson(const Json::Value& node,
+    std::string parent_key, ThemeInfoBuilder* builder) {
+  bool ret = true;
+  for (auto it = node.begin(); it != node.end(); ++it) {
+    std::string key = parent_key.empty() ?
+          it.name() : parent_key + "/" + it.name();
+    if (it->isObject())
+      ret &= ExtractJson(*it, key, builder);
+    else if (it->isArray())
+      ret &= ExtractArray(*it, key, builder);
+    else
+      ret &= ExtractElement(*it, key, builder);
+  }
+  return ret;
+}
+
 loader::ThemeInfo ThemeParser::Inflate(const std::string id,
     const std::string pkgid, uid_t uid, bool is_default) {
   Json::CharReaderBuilder rbuilder;
@@ -32,16 +90,15 @@ loader::ThemeInfo ThemeParser::Inflate(const std::string id,
     ifs.close();
     return {};
   }
-
-  // FIXME: this parser should parse more theme information.
   ThemeInfoBuilder builder(id);
   builder.PutString("pkgid", pkgid).
       PutString("uid", std::to_string(uid)).
-      PutString("is_default", is_default ? "true" : "false").
-      PutString("version", root["version"].asString()).
-      PutString("tool_version", root["tool_version"].asString()).
-      PutString("title", root["header"]["title"].asString()).
-      PutString("description", root["header"]["description"].asString());
+      PutString("is_default", is_default ? "true" : "false");
+
+  if (!ExtractJson(root, "", &builder)) {
+    LOG(ERROR) << "Fail to extract json value";
+    return {};
+  }
 
   return builder.Build();
 }
index 65d07ac..e1f486f 100644 (file)
@@ -5,12 +5,14 @@
 #ifndef THEME_PLUGIN_THEME_PARSER_H_
 #define THEME_PLUGIN_THEME_PARSER_H_
 
+#include <json/json.h>
 #include <sys/types.h>
 
 #include <memory>
 #include <string>
 
 #include "theme/loader/theme_info.h"
+#include "theme_plugin/theme_info_builder.h"
 
 namespace ttm {
 namespace plugin {
@@ -29,6 +31,13 @@ class ThemeParser {
   bool Commit(ThemeOperation operation, const loader::ThemeInfo& theme);
 
  private:
+  bool ExtractArray(const Json::Value& node,
+      std::string parent_key, ThemeInfoBuilder* builder);
+  bool ExtractElement(const Json::Value &node,
+      const std::string parent_key, ThemeInfoBuilder* builder);
+  bool ExtractJson(const Json::Value& node,
+      std::string parent_key, ThemeInfoBuilder* builder);
+
   std::string path_;
 };
 
diff --git a/test/unit_tests/test_samples/test_different_array_element_type.json b/test/unit_tests/test_samples/test_different_array_element_type.json
new file mode 100644 (file)
index 0000000..e7f8f00
--- /dev/null
@@ -0,0 +1,6 @@
+{
+        "array" : [
+                "a",
+                1
+        ]
+}
diff --git a/test/unit_tests/test_samples/test_empty_array.json b/test/unit_tests/test_samples/test_empty_array.json
new file mode 100644 (file)
index 0000000..b503cc6
--- /dev/null
@@ -0,0 +1,4 @@
+{
+        "array" : [
+        ]
+}
diff --git a/test/unit_tests/test_samples/test_invalid_json.json b/test/unit_tests/test_samples/test_invalid_json.json
new file mode 100644 (file)
index 0000000..421be19
--- /dev/null
@@ -0,0 +1,3 @@
+{
+        "invalid"
+}
diff --git a/test/unit_tests/test_samples/test_multidimensional_array.json b/test/unit_tests/test_samples/test_multidimensional_array.json
new file mode 100644 (file)
index 0000000..f892150
--- /dev/null
@@ -0,0 +1,18 @@
+{
+        "1D_array" : ["1", "2", "3"],
+        "2D_array" : [
+                ["1", "2", "3"],
+                ["1", "2", "3"]
+        ],
+        "3D_array" : [
+                [
+                        ["1", "2", "3"],
+                        ["1", "2", "3"]
+                ],
+                [
+                        ["1", "2", "3"],
+                        ["1", "2", "3"]
+                ]
+
+        ]
+}
index 7948970..6938598 100644 (file)
@@ -1,9 +1,9 @@
 {
         "version": "1.0.0",
         "tool_version": "1.00.38.820793",
+        "title": "GOGO Theme",
+        "description": "Example for theme spec",
         "header": {
-                "title": "GOGO Theme",
-                "description": "Example for theme spec",
                 "profile": "wearable",
                 "resolutions": [
                         "720x1280"
@@ -35,4 +35,4 @@
                         }
                 }
         ]
-}
\ No newline at end of file
+}
index 5417be0..5185d30 100644 (file)
@@ -19,6 +19,9 @@
 #include "theme/loader/theme_info.h"
 #include "theme_plugin/theme_parser.h"
 
+#include <string>
+#include <vector>
+
 class ThemeParserTest : public testing::Test {
  public:
   virtual ~ThemeParserTest() {}
@@ -40,4 +43,59 @@ TEST_F(ThemeParserTest, Inflate) {
   EXPECT_EQ(info.GetToolVersion(), "1.00.38.820793");
   EXPECT_EQ(info.GetTitle(), "GOGO Theme");
   EXPECT_EQ(info.GetDescription(), "Example for theme spec");
+  EXPECT_EQ(info.GetString("header/profile"), "wearable");
+  EXPECT_EQ(info.GetString("themes/0/home/app_tray"), "tray.png");
+  EXPECT_EQ(info.GetString("themes/0/home/appicon/org.tizen.browser"),
+      "browser.png");
+  EXPECT_EQ(info.GetString("themes/0/home/appicon/org.tizen.calculator"),
+      "calculator.png");
+  EXPECT_EQ(info.GetString("themes/0/home/appicon/org.tizen.calendar"),
+      "calendar.png");
+  EXPECT_EQ(info.GetString("themes/0/home/appicon/org.tizen.clock"),
+      "clock.png");
+  EXPECT_EQ(info.GetString("themes/0/home/appicon/org.tizen.contact"),
+      "contact.png");
+  EXPECT_EQ(info.GetString("themes/0/home/size"), "30");
+  EXPECT_EQ(info.GetString("themes/0/home/wallpaper"), "home_wallpaper.png");
+  EXPECT_EQ(info.GetString("themes/0/keyboard/keypad_bg_color"), "#050a28");
+  EXPECT_EQ(info.GetString("themes/0/watchface/id"), "org.tizen.gogowatch");
+  EXPECT_EQ(info.GetString("themes/0/watchface/url"),
+      "https://www.download.gogowatch/get");
+  EXPECT_EQ(info.GetStringArray("themes/0/preview"),
+      std::vector<std::string>({"GOGO_Preview.png"}));
+}
+
+TEST_F(ThemeParserTest, MultidimensionalArray) {
+  ttm::plugin::ThemeParser parser(
+      "test_samples/test_multidimensional_array.json");
+  auto info = parser.Inflate("testid", "testpkgid", 5001, false);
+  std::vector<std::string> array_value({"1", "2", "3"});
+  EXPECT_EQ(info.GetStringArray("1D_array"), array_value);
+  EXPECT_EQ(info.GetStringArray("2D_array/0"), array_value);
+  EXPECT_EQ(info.GetStringArray("2D_array/1"), array_value);
+  EXPECT_EQ(info.GetStringArray("3D_array/0/0"), array_value);
+  EXPECT_EQ(info.GetStringArray("3D_array/0/1"), array_value);
+  EXPECT_EQ(info.GetStringArray("3D_array/1/0"), array_value);
+  EXPECT_EQ(info.GetStringArray("3D_array/1/1"), array_value);
+}
+
+TEST_F(ThemeParserTest, InvalidJson) {
+  ttm::plugin::ThemeParser parser(
+      "test_samples/test_invalid_json.json");
+  auto info = parser.Inflate("testid", "testpkgid", 5001, false);
+  EXPECT_FALSE(info.IsValid());
+}
+
+TEST_F(ThemeParserTest, DifferentArrayElementType) {
+  ttm::plugin::ThemeParser parser(
+      "test_samples/test_different_array_element_type.json");
+  auto info = parser.Inflate("testid", "testpkgid", 5001, false);
+  EXPECT_FALSE(info.IsValid());
+}
+
+TEST_F(ThemeParserTest, EmptyArray) {
+  ttm::plugin::ThemeParser parser(
+      "test_samples/test_empty_array.json");
+  auto info = parser.Inflate("testid", "testpkgid", 5001, false);
+  EXPECT_FALSE(info.IsValid());
 }