Add uuid UDA type (#3827)

Mainly so that UDAs that refer to another task can be formated as
"short".
This commit is contained in:
Ram-Z 2025-04-21 01:51:38 +01:00 committed by GitHub
parent bae37d9448
commit 31829d61fc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 107 additions and 12 deletions

View file

@ -1384,7 +1384,7 @@ if you define a UDA named 'estimate', Taskwarrior will not know that this value
is weeks, hours, minutes, money, or some other resource count.
.TP
.B uda.<name>.type=string|numeric|date|duration
.B uda.<name>.type=string|numeric|uuid|date|duration
.RS
Defines a UDA called '<name>', of the specified type.
.RE

View file

@ -1999,7 +1999,7 @@ void Task::modify(modType type, bool text_required /* = false */) {
// Delegate modification to the column object or their base classes.
if (name == "depends" || name == "tags" || name == "recur" || column->type() == "date" ||
column->type() == "duration" || column->type() == "numeric" ||
column->type() == "string") {
column->type() == "string" || column->type() == "uuid") {
column->modify(*this, value);
mods = true;
}

View file

@ -297,3 +297,23 @@ void ColumnUDADuration::render(std::vector<std::string>& lines, Task& task, int
}
////////////////////////////////////////////////////////////////////////////////
ColumnUDAUUID::ColumnUDAUUID() {
_name = "<uda>";
_type = "uuid";
_style = "long";
_label = "";
_modifiable = true;
_uda = true;
_styles = {"long", "short"};
_examples = {"f30cb9c3-3fc0-483f-bfb2-3bf134f00694", "f30cb9c3"};
}
////////////////////////////////////////////////////////////////////////////////
bool ColumnUDAUUID::validate(const std::string& input) const {
Lexer lex(input);
std::string token;
Lexer::Type type;
return lex.isUUID(token, type, true);
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -31,6 +31,7 @@
#include <ColTypeDuration.h>
#include <ColTypeNumeric.h>
#include <ColTypeString.h>
#include <ColUUID.h>
////////////////////////////////////////////////////////////////////////////////
class ColumnUDAString : public ColumnTypeString {
@ -83,5 +84,12 @@ class ColumnUDADuration : public ColumnTypeDuration {
std::vector<std::string> _values;
};
////////////////////////////////////////////////////////////////////////////////
class ColumnUDAUUID : public ColumnUUID {
public:
ColumnUDAUUID();
bool validate(const std::string&) const;
};
#endif
////////////////////////////////////////////////////////////////////////////////

View file

@ -246,9 +246,15 @@ Column* Column::uda(const std::string& name) {
c->_label = label;
if (values != "") c->_values = split(values, ',');
return c;
} else if (type == "uuid") {
auto c = new ColumnUDAUUID();
c->_name = name;
c->_label = label;
return c;
} else if (type != "")
throw std::string(
"User defined attributes may only be of type 'string', 'date', 'duration' or 'numeric'.");
"User defined attributes may only be of type 'string', 'uuid', date', 'duration' or "
"'numeric'.");
return nullptr;
}

View file

@ -109,29 +109,26 @@ class TestUUIDFormats(TestCase):
def setUpClass(cls):
"""Executed once before any test in the class"""
cls.t = Task()
cls.t.config("report.xxx.columns", "id,uuid")
cls.t.config("report.xxx.columns", "uuid")
cls.t.config("verbose", "nothing")
cls.t("add zero")
code, out, err = cls.t("_get 1.uuid")
cls.uuid = out.strip()
def setUp(self):
"""Executed before each test in the class"""
def test_uuid_long(self):
"""Verify formatting of 'uuid.long' column"""
code, out, err = self.t("xxx rc.report.xxx.columns:id,uuid.long")
self.assertIn(self.uuid, out)
code, out, err = self.t("xxx rc.report.xxx.columns:uuid.long")
self.assertEqual(self.uuid, out.strip())
def test_uuid_short(self):
"""Verify formatting of 'uuid.short' column"""
code, out, err = self.t("xxx rc.report.xxx.columns:id,uuid.short")
self.assertIn(self.uuid[:7], out)
code, out, err = self.t("xxx rc.report.xxx.columns:uuid.short")
self.assertEqual(self.uuid[:8], out.strip())
def test_uuid_format_unrecognized(self):
"""Verify uuid.donkey formatting fails"""
code, out, err = self.t.runError("xxx rc.report.xxx.columns:id,uuid.donkey")
code, out, err = self.t.runError("xxx rc.report.xxx.columns:uuid.donkey")
self.assertEqual(err, "Unrecognized column format 'uuid.donkey'\n")
@ -482,6 +479,70 @@ start active* ✓
"""
class TestUDAUUIDFormats(TestCase):
@classmethod
def setUpClass(cls):
"""Executed once before any test in the class"""
cls.t = Task()
cls.t.config("verbose", "nothing")
cls.t.config("uda.uda_uuid.label", "uda_uuid")
cls.t.config("uda.uda_uuid.type", "uuid")
cls.t.config("report.xxx.columns", "uda_uuid")
cls.t("add zero")
code, out, err = cls.t("_get 1.uuid")
cls.t("add uda_uuid:{} one".format(out.strip()))
code, out, err = cls.t("_get 2.uda_uuid")
cls.uda_uuid = out.strip()
def test_uda_uuid_invalid_fails(self):
"""Verify adding invalid uuid fails"""
code, out, err = self.t.runError("add uda_uuid:shrek three")
self.assertNotEqual(code, 0)
self.assertIn("uda_uuid", err.strip())
self.assertIn("shrek", err.strip())
def test_uda_uuid_long(self):
"""Verify formatting of 'uda_uuid.long' column"""
code, out, err = self.t("2 xxx rc.report.xxx.columns:uda_uuid.long")
self.assertEqual(self.uda_uuid, out.strip())
def test_uda_uuid_short(self):
"""Verify formatting of 'uda_uuid.short' column"""
code, out, err = self.t("2 xxx rc.report.xxx.columns:uda_uuid.short")
self.assertEqual(self.uda_uuid[:8], out.strip())
def test_uda_uuid_format_unrecognized(self):
"""Verify uda_uuid.donkey formatting fails"""
code, out, err = self.t.runError("xxx rc.report.xxx.columns:id,uda_uuid.donkey")
self.assertEqual(err, "Unrecognized column format 'uda_uuid.donkey'\n")
class TestUDAUUIDReconfiguredFromString(TestCase):
@classmethod
def setUpClass(cls):
"""Executed once before any test in the class"""
cls.t = Task()
cls.t.config("verbose", "nothing")
cls.t.config("uda.uda_uuid.label", "uda_uuid")
cls.t.config("report.xxx.columns", "uda_uuid")
cls.t.config("uda.uda_uuid.type", "string")
cls.expected_str = 3 * "littlepigs"
cls.t("add uda_uuid:{} one".format(cls.expected_str))
cls.t.config("uda.uda_uuid.type", "uuid")
def test_uda_uuid_long(self):
"""Verify formatting of 'uda_uuid.long' column"""
code, out, err = self.t("1 xxx rc.report.xxx.columns:uda_uuid.long")
self.assertEqual(self.expected_str, out.strip())
def test_uda_uuid_short(self):
"""Verify formatting of 'uda_uuid.short' column"""
code, out, err = self.t("1 xxx rc.report.xxx.columns:uda_uuid.short")
self.assertEqual(self.expected_str[:8], out.strip())
class TestFeature1061(TestCase):
def setUp(self):
"""Executed before each test in the class"""