mirror of
https://github.com/GothenburgBitFactory/timewarrior.git
synced 2025-06-26 10:54:28 +02:00
Use json::{encode|decode} for reading / writing JSON.
The JSON library in libshared has functions to esacpe JSON's special characters, but they are not used by default. Closes #416 Related to #261 Signed-off-by: Shaun Ruffell <sruffell@sruffell.net>
This commit is contained in:
parent
2897379b14
commit
fd6d57dbc2
5 changed files with 84 additions and 6 deletions
|
@ -477,7 +477,7 @@ void Database::initializeTagDatabase ()
|
|||
|
||||
for (auto &pair : json->_data)
|
||||
{
|
||||
auto key = str_replace (pair.first, "\\\"", "\"");
|
||||
auto key = json::decode (pair.first);
|
||||
auto *value = (json::object *) pair.second;
|
||||
auto iter = value->_data.find ("count");
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ std::string Interval::json () const
|
|||
if (tags[0])
|
||||
tags += ',';
|
||||
|
||||
tags += "\"" + escape (tag, '"') + "\"";
|
||||
tags += "\"" + json::encode (tag) + "\"";
|
||||
}
|
||||
|
||||
out << ",\"tags\":["
|
||||
|
@ -153,7 +153,7 @@ std::string Interval::json () const
|
|||
|
||||
if (!annotation.empty ())
|
||||
{
|
||||
out << ",\"annotation\":\"" << escape (annotation, '"') << "\"";
|
||||
out << ",\"annotation\":\"" << json::encode (annotation) << "\"";
|
||||
}
|
||||
}
|
||||
out << "}";
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <Lexer.h>
|
||||
#include <IntervalFactory.h>
|
||||
#include <JSON.h>
|
||||
#include <shared.h>
|
||||
|
||||
static std::vector <std::string> tokenizeSerialization (const std::string& line)
|
||||
{
|
||||
|
@ -136,12 +137,12 @@ Interval IntervalFactory::fromJson (const std::string& jsonString)
|
|||
for (auto& tag : tags->_data)
|
||||
{
|
||||
auto* value = (json::string*) tag;
|
||||
interval.tag(value->_data);
|
||||
interval.tag (json::decode (value->_data));
|
||||
}
|
||||
}
|
||||
|
||||
json::string* annotation = (json::string*) json->_data["annotation"];
|
||||
interval.annotation = (annotation != nullptr) ? annotation->_data : "";
|
||||
interval.annotation = (annotation != nullptr) ? json::decode (annotation->_data) : "";
|
||||
|
||||
json::string* start = (json::string*) json->_data["start"];
|
||||
interval.start = (start != nullptr) ? Datetime(start->_data) : 0;
|
||||
|
|
|
@ -24,9 +24,11 @@
|
|||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <JSON.h>
|
||||
#include <TagInfoDatabase.h>
|
||||
#include <format.h>
|
||||
#include <TagInfo.h>
|
||||
|
||||
#include "timew.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -117,7 +119,7 @@ std::string TagInfoDatabase::toJson ()
|
|||
if (tagInfo.hasCount ())
|
||||
{
|
||||
json << (first ? "" : ",")
|
||||
<< "\n \"" << escape(pair.first, '"') << "\":"
|
||||
<< "\n \"" << json::encode (pair.first) << "\":"
|
||||
<< tagInfo.toJson ();
|
||||
|
||||
first = (first ? false : first);
|
||||
|
|
75
test/undo.t
75
test/undo.t
|
@ -68,6 +68,36 @@ class TestUndo(TestCase):
|
|||
expectedEnd=one_hour_before_utc,
|
||||
expectedAnnotation="")
|
||||
|
||||
def test_undo_annotate_with_embedded_quotes(self):
|
||||
"""Test undo of command 'annotate' with embedded quotes"""
|
||||
now_utc = datetime.now().utcnow()
|
||||
one_hour_before_utc = now_utc - timedelta(hours=1)
|
||||
two_hours_before_utc = now_utc - timedelta(hours=2)
|
||||
|
||||
self.t("start {:%Y%m%dT%H%M%SZ} foo".format(two_hours_before_utc))
|
||||
self.t("start {:%Y%m%dT%H%M%SZ} bar".format(one_hour_before_utc))
|
||||
self.t("annotate 'foo \"bar\"'")
|
||||
|
||||
j = self.t.export()
|
||||
self.assertEqual(len(j), 2, msg="Expected 2 intervals before, got {}".format(len(j)))
|
||||
self.assertClosedInterval(j[0],
|
||||
expectedStart=two_hours_before_utc,
|
||||
expectedEnd=one_hour_before_utc,
|
||||
expectedTags=["foo"])
|
||||
self.assertOpenInterval(j[1],
|
||||
expectedStart=one_hour_before_utc,
|
||||
expectedTags=["bar"],
|
||||
expectedAnnotation="foo \"bar\"")
|
||||
|
||||
self.t("undo")
|
||||
|
||||
j = self.t.export()
|
||||
self.assertOpenInterval(j[1],
|
||||
expectedStart=one_hour_before_utc,
|
||||
expectedTags=["bar"],
|
||||
expectedAnnotation="")
|
||||
|
||||
|
||||
def test_undo_cancel(self):
|
||||
"""Test undo of command 'cancel'"""
|
||||
one_hour_before_utc = datetime.now().utcnow() - timedelta(hours=1)
|
||||
|
@ -422,6 +452,51 @@ class TestUndo(TestCase):
|
|||
expectedStart=two_hours_before_utc,
|
||||
expectedTags=["foo"])
|
||||
|
||||
def test_undo_start_with_embedded_quotes_in_tag(self):
|
||||
"""Test undo of 'start' with embedded quotes in tag"""
|
||||
now_utc = datetime.now().utcnow()
|
||||
one_hour_before_utc = now_utc - timedelta(hours=1)
|
||||
two_hours_before_utc = now_utc - timedelta(hours=2)
|
||||
|
||||
self.t("start {:%Y%m%dT%H%M%SZ} foo".format(two_hours_before_utc))
|
||||
self.t("start {:%Y%m%dT%H%M%SZ} 'test \"this quoted\" string'".format(one_hour_before_utc))
|
||||
|
||||
j = self.t.export()
|
||||
self.assertEqual(len(j), 2, msg="Expected 2 intervals before, got {}".format(len(j)))
|
||||
self.assertClosedInterval(j[0],
|
||||
expectedStart=two_hours_before_utc,
|
||||
expectedEnd=one_hour_before_utc,
|
||||
expectedTags=["foo"])
|
||||
self.assertOpenInterval(j[1],
|
||||
expectedStart=one_hour_before_utc,
|
||||
expectedTags=["test \"this quoted\" string"])
|
||||
|
||||
self.t("undo")
|
||||
|
||||
j = self.t.export()
|
||||
self.assertEqual(len(j), 1, msg="Expected 1 interval afterwards, got {}".format(len(j)))
|
||||
self.assertOpenInterval(j[0],
|
||||
expectedStart=two_hours_before_utc,
|
||||
expectedTags=["foo"])
|
||||
|
||||
def test_undo_start_with_tag_enclosed_in_backslashes(self):
|
||||
"""Test undo of 'start' with tag enclosed in backslashes"""
|
||||
now_utc = datetime.now().utcnow()
|
||||
one_hour_before_utc = now_utc - timedelta(hours=1)
|
||||
|
||||
self.t("start {:%Y%m%dT%H%M%SZ} '\\foo\\'".format(one_hour_before_utc))
|
||||
|
||||
j = self.t.export()
|
||||
self.assertEqual(len(j), 1, msg="Expected 1 intervals before, got {}".format(len(j)))
|
||||
self.assertOpenInterval(j[0],
|
||||
expectedStart=one_hour_before_utc,
|
||||
expectedTags=["\\foo\\"])
|
||||
|
||||
self.t("undo")
|
||||
|
||||
j = self.t.export()
|
||||
self.assertEqual(len(j), 0, msg="Expected 0 interval afterwards, got {}".format(len(j)))
|
||||
|
||||
def test_undo_stop(self):
|
||||
"""Test undo of command 'stop'"""
|
||||
now_utc = datetime.now().utcnow()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue