From 34e20ab14c88e19b75428248962af9dc0a94bed2 Mon Sep 17 00:00:00 2001 From: Sarah Date: Sun, 2 Apr 2023 11:23:05 +0100 Subject: [PATCH 1/3] allow model history without creator --- src/sbml/SBase.cpp | 80 +++++++ src/sbml/SBase.h | 103 +++++++++ src/sbml/annotation/RDFAnnotationParser.cpp | 200 +++++++++--------- .../test/TestUnusualRDFAnnotation.cpp | 110 ++++++++++ .../test/test-data/model_history_dates.xml | 21 ++ .../test/test-data/set_annot_test.xml | 50 ++--- 6 files changed, 440 insertions(+), 124 deletions(-) create mode 100644 src/sbml/annotation/test/test-data/model_history_dates.xml diff --git a/src/sbml/SBase.cpp b/src/sbml/SBase.cpp index d6d2f1498c..3753d9b703 100644 --- a/src/sbml/SBase.cpp +++ b/src/sbml/SBase.cpp @@ -1064,6 +1064,31 @@ SBase::getModelHistory() return mHistory; } +Date* +SBase::getCreatedDate() const +{ + return (mHistory != NULL) ? mHistory->getCreatedDate() : NULL; +} + +Date* +SBase::getCreatedDate() +{ + return (mHistory != NULL) ? mHistory->getCreatedDate() : NULL; +} + + +Date* +SBase::getModifiedDate(unsigned int n) +{ + return (mHistory != NULL) ? mHistory->getModifiedDate(n) : NULL; +} + +unsigned int +SBase::getNumModifiedDates() +{ + return (mHistory != NULL) ? mHistory->getNumModifiedDates() : NULL; +} + /* * @return @c true if the metaid of this SBML object is set, false @@ -1150,6 +1175,22 @@ SBase::isSetModelHistory() const } +bool +SBase::isSetCreatedDate() const +{ + return (mHistory == NULL) ? false : mHistory->isSetCreatedDate(); +} + + + +bool +SBase::isSetModifiedDate() const +{ + return (mHistory == NULL) ? false : mHistory->isSetModifiedDate(); +} + + + /* * Sets the metaid field of the given SBML object to a copy of metaid. */ @@ -2310,6 +2351,45 @@ SBase::setModelHistory(ModelHistory * history) return status; } +int +SBase::setCreatedDate(Date* date) +{ + if (mHistory != NULL) + { + return mHistory->setCreatedDate(date); + } + else + { + ModelHistory* mh = new ModelHistory(); + // we want to set it regardless of content + mHistory = static_cast(mh->clone()); + mHistoryChanged = true; + delete mh; + + return mHistory->setCreatedDate(date); + + } +} + +int +SBase::addModifiedDate(Date* date) +{ + if (mHistory != NULL) + { + return mHistory->addModifiedDate(date); + } + else + { + ModelHistory* mh = new ModelHistory(); + // we want to set it regardless of content + mHistory = static_cast(mh->clone()); + mHistoryChanged = true; + delete mh; + + return mHistory->addModifiedDate(date); + + } +} /** @cond doxygenLibsbmlInternal */ /* diff --git a/src/sbml/SBase.h b/src/sbml/SBase.h index ce7e00f080..b367bbed34 100644 --- a/src/sbml/SBase.h +++ b/src/sbml/SBase.h @@ -975,6 +975,19 @@ class LIBSBML_EXTERN SBase ModelHistory* getModelHistory() const; + /** + * Returns the "creation date" portion of the ModelHistory of this object. + * + * @return a Date object representing the creation date stored in + * this ModelHistory object. + * + * @note In SBML Level 2, model history annotations were only + * permitted on the Model element. In SBML Level 3, they are + * permitted on all SBML components derived from SBase. + */ + Date * getCreatedDate() const; + + /** * Returns the ModelHistory object, if any, attached to this object. * @@ -988,6 +1001,46 @@ class LIBSBML_EXTERN SBase ModelHistory* getModelHistory(); + /** + * Returns the "creation date" portion of the ModelHistory of this object. + * + * @return a Date object representing the creation date stored in + * this ModelHistory object. + * + * @note In SBML Level 2, model history annotations were only + * permitted on the Model element. In SBML Level 3, they are + * permitted on all SBML components derived from SBase. + */ + Date * getCreatedDate(); + + + /** + * Get the nth Date object in the list of "modified date" values stored + * in the ModelHistory of this object. + * + * In the MIRIAM format for annotations, there can be multiple + * modification dates. The libSBML ModelHistory class supports this by + * storing a list of "modified date" values. + * + * @return the nth Date in the list of ModifiedDates of this + * ModelHistory or @c NULL if no such object exists. + */ + Date* getModifiedDate(unsigned int n); + + + /** + * Get the number of Date objects in the ModelHistory of this Iobject's list of + * "modified dates". + * + * In the MIRIAM format for annotations, there can be multiple + * modification dates. The libSBML ModelHistory class supports this by + * storing a list of "modified date" values. + * + * @return the number of ModifiedDates in this ModelHistory. + */ + unsigned int getNumModifiedDates(); + + /** * Predicate returning @c true if this object's "metaid" attribute is set. * @@ -1163,6 +1216,30 @@ class LIBSBML_EXTERN SBase bool isSetModelHistory() const; + /** + * Predicate returning @c true if this + * object has a ModelHistory object attached to it and the created date is set + * + * @return @c true if the CreatedDate of the ModelHistory of this object is set, + * @c false otherwise. + * + * @note In SBML Level 2, model history annotations were only + * permitted on the Model element. In SBML Level 3, they are + * permitted on all SBML components derived from SBase. + */ + bool isSetCreatedDate() const; + + + /** + * Predicate returning @c true or @c false depending on whether the + * ModelHistory's "modified date" of this object is set. + * + * @return @c true if the modification date value of this ModelHistory + * object is set, @c false otherwise. + */ + bool isSetModifiedDate() const; + + /** * Sets the value of the "id" attribute of this SBML object. * @@ -1697,6 +1774,32 @@ s.setNotes("

here is my note

getNumCreators(); n++) + if (history->getNumCreators() > 0) { - XMLNode * N = 0; - XMLNode * Email = 0; - XMLNode * Org = 0; - - ModelCreator* c = history->getCreator(n); - if (c->usingFNVcard4()) + for (unsigned int n = 0; n < history->getNumCreators(); n++) { - if (c->usingSingleName()) + XMLNode * N = 0; + XMLNode * Email = 0; + XMLNode * Org = 0; + + ModelCreator* c = history->getCreator(n); + if (c->usingFNVcard4()) { - // we want to a single name but we have entered it as two - std::string name = c->getName(); - if (name != c->getGivenName()) + if (c->usingSingleName()) { - name = c->getGivenName() + " " + c->getFamilyName(); - } - XMLNode empty(empty_token); - empty.append(name); + // we want to a single name but we have entered it as two + std::string name = c->getName(); + if (name != c->getGivenName()) + { + name = c->getGivenName() + " " + c->getFamilyName(); + } + XMLNode empty(empty_token); + empty.append(name); - XMLNode Text(Text_token); - Text.addChild(empty); + XMLNode Text(Text_token); + Text.addChild(empty); - N = new XMLNode(Fn_token); - N->addChild(Text); - } - } - else - { - std::string name = c->getName(); - std::string fname, gname; - // we have entered one name but want to display it as 2 - if (name == c->getGivenName()) - { - std::size_t found = name.find(" "); - gname = name.substr(0, found); - fname = name.substr(found + 1); - c->setFamilyName(fname); - c->setGivenName(gname); + N = new XMLNode(Fn_token); + N->addChild(Text); + } } - if (c->isSetFamilyName()) + else { - XMLNode empty(empty_token); - empty.append(c->getFamilyName()); + std::string name = c->getName(); + std::string fname, gname; + // we have entered one name but want to display it as 2 + if (name == c->getGivenName()) + { + std::size_t found = name.find(" "); + gname = name.substr(0, found); + fname = name.substr(found + 1); + c->setFamilyName(fname); + c->setGivenName(gname); + } + if (c->isSetFamilyName()) + { + XMLNode empty(empty_token); + empty.append(c->getFamilyName()); + + XMLNode Family(Family_token); + Family.addChild(empty); - XMLNode Family(Family_token); - Family.addChild(empty); + N = new XMLNode(N_token); + N->addChild(Family); + } + + if (c->isSetGivenName()) + { + XMLNode empty(empty_token); + empty.append(c->getGivenName()); - N = new XMLNode(N_token); - N->addChild(Family); + XMLNode Given(Given_token); + Given.addChild(empty); + + if (N == NULL) + { + N = new XMLNode(N_token); + } + N->addChild(Given); + } } - if (c->isSetGivenName()) + if (c->isSetEmail()) { XMLNode empty(empty_token); - empty.append(c->getGivenName()); + empty.append(c->getEmail()); - XMLNode Given(Given_token); - Given.addChild(empty); + Email = new XMLNode(Email_token); + Email->addChild(empty); + } - if (N == NULL) + if (c->isSetOrganisation()) + { + if (use_vcard3) { - N = new XMLNode(N_token); - } - N->addChild(Given); - } - } + XMLNode empty(empty_token); + empty.append(c->getOrganisation()); + XMLNode Orgname(Orgname_token); + Orgname.addChild(empty); - if (c->isSetEmail()) - { - XMLNode empty(empty_token); - empty.append(c->getEmail()); + Org = new XMLNode(Org_token); + Org->addChild(Orgname); + } + else + { + XMLNode empty(empty_token); + empty.append(c->getOrganisation()); - Email = new XMLNode(Email_token); - Email->addChild(empty); - } + Org = new XMLNode(Org_token); + Org->addChild(empty); + } + } - if (c->isSetOrganisation()) - { - if (use_vcard3) + XMLNode li(li_token); + if (N != NULL) { - XMLNode empty(empty_token); - empty.append(c->getOrganisation()); - XMLNode Orgname(Orgname_token); - Orgname.addChild(empty); - - Org = new XMLNode(Org_token); - Org->addChild(Orgname); + li.addChild(*N); + delete N; } - else + if (Email != NULL) { - XMLNode empty(empty_token); - empty.append(c->getOrganisation()); - - Org = new XMLNode(Org_token); - Org->addChild(empty); + li.addChild(*Email); + delete Email; + } + if (Org != NULL) + { + li.addChild(*Org); + delete Org; + } + if (c->getAdditionalRDF() != NULL) + { + li.addChild(*(c->getAdditionalRDF())); } - } - XMLNode li(li_token); - if (N != NULL) - { - li.addChild(*N); - delete N; - } - if (Email != NULL) - { - li.addChild(*Email); - delete Email; - } - if (Org != NULL) - { - li.addChild(*Org); - delete Org; - } - if (c->getAdditionalRDF() != NULL) - { - li.addChild(*(c->getAdditionalRDF())); + bag.addChild(li); } - bag.addChild(li); + XMLNode creator(creator_token); + creator.addChild(bag); + description->addChild(creator); } - - XMLNode creator(creator_token); - creator.addChild(bag); - description->addChild(creator); - /* created date */ if (history->isSetCreatedDate()) { diff --git a/src/sbml/annotation/test/TestUnusualRDFAnnotation.cpp b/src/sbml/annotation/test/TestUnusualRDFAnnotation.cpp index cb34271faf..bd71b727bc 100644 --- a/src/sbml/annotation/test/TestUnusualRDFAnnotation.cpp +++ b/src/sbml/annotation/test/TestUnusualRDFAnnotation.cpp @@ -63,6 +63,8 @@ CK_CPPSTART static Model *m; static SBMLDocument* d; +static Model *m1; +static SBMLDocument* d1; extern char *TestDataDirectory; @@ -76,12 +78,16 @@ void UnusualRDFAnnotation_setup (void) { char *filename = safe_strcat(TestDataDirectory, "set_annot_test.xml"); + char *filename1 = safe_strcat(TestDataDirectory, "model_history_dates.xml"); // The following will return a pointer to a new SBMLDocument. d = readSBML(filename); m = d->getModel(); + d1 = readSBML(filename1); + m1 = d1->getModel(); free(filename); + free(filename1); } @@ -89,6 +95,7 @@ void UnusualRDFAnnotation_teardown (void) { delete d; + delete d1; } static bool @@ -276,6 +283,104 @@ START_TEST(test_set_annotation) END_TEST +START_TEST(test_roundtrip_mh_dates) +{ + const char * expected = "\n" + " \n" + " \n" + " \n" + " \n" + " 2005-02-02T14:56:11Z\n" + " \n" + " \n" + " 2006-05-30T10:46:02Z\n" + " \n" + " \n" + " \n" + " \n" + "" + ; + + Compartment *c = m1->getCompartment(0); + + fail_unless(equals(expected, c->toSBML())); +} +END_TEST + + +START_TEST(test_has_dates) +{ + Compartment *c = m1->getCompartment(0); + + fail_unless(c->isSetModelHistory() == true); + fail_unless(c->isSetCreatedDate() == true); + fail_unless(c->isSetModifiedDate() == true); + + ModelHistory *mh = c->getModelHistory(); + fail_unless(mh->getNumCreators() == 0); + fail_unless(mh->getCreatedDate()->getDateAsString() == "2005-02-02T14:56:11Z"); + fail_unless(mh->getNumModifiedDates() == 1); + fail_unless(mh->getModifiedDate(0)->getDateAsString() == "2006-05-30T10:46:02Z"); + fail_unless(mh->getModifiedDate(1) == NULL); + + fail_unless(c->getCreatedDate()->getDateAsString() == "2005-02-02T14:56:11Z"); + fail_unless(c->getNumModifiedDates() == 1); + fail_unless(c->getModifiedDate(0)->getDateAsString() == "2006-05-30T10:46:02Z"); + fail_unless(c->getModifiedDate(1) == NULL); +} +END_TEST + + +START_TEST(test_no_dates) +{ + fail_unless(m1->isSetModelHistory() == false); + fail_unless(m1->isSetCreatedDate() == false); + fail_unless(m1->isSetModifiedDate() == false); + + ModelHistory *mh = m1->getModelHistory(); + fail_unless(mh == NULL); + + fail_unless(m1->getCreatedDate() == NULL); + fail_unless(m1->getNumModifiedDates() == 0); + fail_unless(m1->getModifiedDate(0) == NULL); +} +END_TEST + + +START_TEST(test_set_dates) +{ + char* original = writeSBMLToString(d1); + + Compartment *c = m1->getCompartment(0); + c->unsetAnnotation(); + + fail_unless(c->isSetAnnotation() == false); + fail_unless(c->isSetModelHistory() == false); + fail_unless(c->isSetCreatedDate() == false); + fail_unless(c->isSetModifiedDate() == false); + fail_unless(c->getNumModifiedDates() == 0); + + Date_t *date = Date_createFromString("2005-02-02T14:56:11"); + fail_unless(c->setCreatedDate(date) == LIBSBML_OPERATION_SUCCESS); + + Date_t *date1 = Date_createFromString("2006-05-30T10:46:02"); + fail_unless(c->addModifiedDate(date1) == LIBSBML_OPERATION_SUCCESS); + + fail_unless(c->isSetAnnotation() == true); + fail_unless(c->isSetModelHistory() == true); + fail_unless(c->isSetCreatedDate() == true); + fail_unless(c->isSetModifiedDate() == true); + fail_unless(c->getNumModifiedDates() == 1); + + fail_unless(equals(original, writeSBMLToString(d1))); + +} +END_TEST Suite * @@ -295,6 +400,11 @@ create_suite_UnusualRDFAnnotation (void) tcase_add_test(tcase, test_read_XMLNode_from_file); tcase_add_test(tcase, test_set_annotation); + tcase_add_test(tcase, test_roundtrip_mh_dates); + tcase_add_test(tcase, test_has_dates); + tcase_add_test(tcase, test_no_dates); + tcase_add_test(tcase, test_set_dates); + suite_add_tcase(suite, tcase); diff --git a/src/sbml/annotation/test/test-data/model_history_dates.xml b/src/sbml/annotation/test/test-data/model_history_dates.xml new file mode 100644 index 0000000000..1a9b3d328d --- /dev/null +++ b/src/sbml/annotation/test/test-data/model_history_dates.xml @@ -0,0 +1,21 @@ + + + + + + + + + + 2005-02-02T14:56:11Z + + + 2006-05-30T10:46:02Z + + + + + + + + diff --git a/src/sbml/annotation/test/test-data/set_annot_test.xml b/src/sbml/annotation/test/test-data/set_annot_test.xml index 466d094ffc..0f83b54a8d 100644 --- a/src/sbml/annotation/test/test-data/set_annot_test.xml +++ b/src/sbml/annotation/test/test-data/set_annot_test.xml @@ -2,33 +2,33 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From ecba830e6359b1a3576148f78a8d1d253a4d2ca2 Mon Sep 17 00:00:00 2001 From: Sarah Date: Mon, 3 Apr 2023 09:56:30 +0100 Subject: [PATCH 2/3] added unset helpers --- src/sbml/SBase.cpp | 69 +++++++++++++++++++ src/sbml/SBase.h | 30 ++++++++ .../test/TestUnusualRDFAnnotation.cpp | 26 +++++++ 3 files changed, 125 insertions(+) diff --git a/src/sbml/SBase.cpp b/src/sbml/SBase.cpp index 3753d9b703..e28212f82d 100644 --- a/src/sbml/SBase.cpp +++ b/src/sbml/SBase.cpp @@ -51,6 +51,7 @@ #include #include +#include #include #include @@ -2972,6 +2973,74 @@ SBase::unsetModelHistory() } +int +SBase::unsetCreatedDate() +{ + if (mHistory != NULL && mHistory->isSetCreatedDate()) + { + mHistoryChanged = true; + } + else + { + return LIBSBML_UNEXPECTED_ATTRIBUTE; + } + + /* ModelHistory is only allowed on Model in L2 + * but on any element in L3 + */ + if (getLevel() < 3 && getTypeCode() != SBML_MODEL) + { + return LIBSBML_UNEXPECTED_ATTRIBUTE; + } + + Date* created = mHistory->getCreatedDate(); + delete created; + mHistory->mCreatedDate = NULL; + + if (mHistory->isSetCreatedDate() == true) + { + return LIBSBML_OPERATION_FAILED; + } + else + { + return LIBSBML_OPERATION_SUCCESS; + } +} + + +int +SBase::unsetModifiedDates() +{ + if (mHistory != NULL && mHistory->isSetModifiedDate()) + { + mHistoryChanged = true; + } + else + { + return LIBSBML_UNEXPECTED_ATTRIBUTE; + } + + /* ModelHistory is only allowed on Model in L2 + * but on any element in L3 + */ + if (getLevel() < 3 && getTypeCode() != SBML_MODEL) + { + return LIBSBML_UNEXPECTED_ATTRIBUTE; + } + + List_freeItems(mHistory->getListModifiedDates(), Date_free, Date_t); + + if (mHistory->getNumModifiedDates() > 0) + { + return LIBSBML_OPERATION_FAILED; + } + else + { + return LIBSBML_OPERATION_SUCCESS; + } +} + + /* * Returns the BiologicalQualifier associated with this resource, * an empty string if the resource does not exist. diff --git a/src/sbml/SBase.h b/src/sbml/SBase.h index b367bbed34..5ed23d9dcb 100644 --- a/src/sbml/SBase.h +++ b/src/sbml/SBase.h @@ -2121,6 +2121,36 @@ s.setNotes("

here is my note

biological qualifier associated with the * given resource. diff --git a/src/sbml/annotation/test/TestUnusualRDFAnnotation.cpp b/src/sbml/annotation/test/TestUnusualRDFAnnotation.cpp index bd71b727bc..ee4e68ad6d 100644 --- a/src/sbml/annotation/test/TestUnusualRDFAnnotation.cpp +++ b/src/sbml/annotation/test/TestUnusualRDFAnnotation.cpp @@ -383,6 +383,31 @@ START_TEST(test_set_dates) END_TEST +START_TEST(test_unset_dates) +{ + Compartment *c = m1->getCompartment(0); + + fail_unless(c->isSetModelHistory() == true); + fail_unless(c->isSetCreatedDate() == true); + fail_unless(c->isSetModifiedDate() == true); + fail_unless(c->getNumModifiedDates() == 1); + Date_t *date1 = Date_createFromString("2006-05-30T10:46:02"); + fail_unless(c->addModifiedDate(date1) == LIBSBML_OPERATION_SUCCESS); + fail_unless(c->getNumModifiedDates() == 2); + + fail_unless(c->unsetCreatedDate() == LIBSBML_OPERATION_SUCCESS); + fail_unless(c->isSetCreatedDate() == false); + + fail_unless(c->unsetModifiedDates() == LIBSBML_OPERATION_SUCCESS); + fail_unless(c->isSetModifiedDate() == false); + fail_unless(c->getNumModifiedDates() == 0); + + delete date1; +} +END_TEST + + + Suite * create_suite_UnusualRDFAnnotation (void) { @@ -404,6 +429,7 @@ create_suite_UnusualRDFAnnotation (void) tcase_add_test(tcase, test_has_dates); tcase_add_test(tcase, test_no_dates); tcase_add_test(tcase, test_set_dates); + tcase_add_test(tcase, test_unset_dates); suite_add_tcase(suite, tcase); From 29e085a8bf9539c6a909b58bac4e60c7640e96ed Mon Sep 17 00:00:00 2001 From: "Frank T. Bergmann" Date: Mon, 3 Apr 2023 11:12:30 +0200 Subject: [PATCH 3/3] simplify allocation --- src/sbml/SBase.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/sbml/SBase.cpp b/src/sbml/SBase.cpp index e28212f82d..48c45ee316 100644 --- a/src/sbml/SBase.cpp +++ b/src/sbml/SBase.cpp @@ -2361,11 +2361,8 @@ SBase::setCreatedDate(Date* date) } else { - ModelHistory* mh = new ModelHistory(); - // we want to set it regardless of content - mHistory = static_cast(mh->clone()); + mHistory = new ModelHistory(); mHistoryChanged = true; - delete mh; return mHistory->setCreatedDate(date); @@ -2381,11 +2378,8 @@ SBase::addModifiedDate(Date* date) } else { - ModelHistory* mh = new ModelHistory(); - // we want to set it regardless of content - mHistory = static_cast(mh->clone()); + mHistory = new ModelHistory(); mHistoryChanged = true; - delete mh; return mHistory->addModifiedDate(date); @@ -2979,7 +2973,7 @@ SBase::unsetCreatedDate() if (mHistory != NULL && mHistory->isSetCreatedDate()) { mHistoryChanged = true; - } + } else { return LIBSBML_UNEXPECTED_ATTRIBUTE; @@ -3014,7 +3008,7 @@ SBase::unsetModifiedDates() if (mHistory != NULL && mHistory->isSetModifiedDate()) { mHistoryChanged = true; - } + } else { return LIBSBML_UNEXPECTED_ATTRIBUTE;