Fossil SCM
Cosmetic and style tweaks in test code.
Commit
4a0be8d60443d58c70a1206acc6a2358d97b5ce6b603fe12ee054f87ac939c93
Parent
830cad5676d99e3…
1 file changed
+65
-55
+65
-55
| --- src/attach.c | ||
| +++ src/attach.c | ||
| @@ -22,32 +22,41 @@ | ||
| 22 | 22 | #include <assert.h> |
| 23 | 23 | |
| 24 | 24 | /* |
| 25 | 25 | ** Given a presumedly legal attachment target name, this guesses the |
| 26 | 26 | ** target type and returns one of CFTYPE_FORUM, CFTYPE_WIKI, |
| 27 | -** CFTYPE_TICKET, or CFTYPE_EVENT. Returns 0 if it cannot | |
| 28 | -** distinguish the target type. | |
| 29 | -** | |
| 30 | -** If bFull is true then it requires zTarget to be an exact matches | |
| 31 | -** for wiki, tech-note, and ticket IDs. If bFull is false then | |
| 32 | -** tech-notes and tickets will perform a prefix match, but it is up to | |
| 33 | -** the caller to provide enough of a prefix to rule out a | |
| 34 | -** collision[^1]. Forum posts are a special case and ignore the bFull | |
| 35 | -** flag. When called repeatedly, this routine can run a bit faster and | |
| 36 | -** more efficiently if bFull is true, but some historical use cases | |
| 37 | -** call for prefix matches. | |
| 38 | -** | |
| 39 | -** In the case of CFTYPE_FORUM, it is up to the caller to ensure that, | |
| 40 | -** if needed, they resolve zTarget using forumpost_head_rid2() so that | |
| 41 | -** they get the RID of the earliest version of the post, as that is | |
| 42 | -** the only one which attachments should target. | |
| 43 | -** | |
| 44 | -** [^1]: Historically (as of 2026-06) attachment target lookups have | |
| 45 | -** used GLOB prefix matching but taken no measures to ensure that the | |
| 46 | -** prefix is unambiguous. Ergo we don't here, either. It is assumed | |
| 47 | -** that the caller passes enough of a prefix to be unambiguous and | |
| 48 | -** that's worked out fine so far. | |
| 27 | +** CFTYPE_TICKET, or CFTYPE_EVENT. Returns 0 if it cannot distinguish | |
| 28 | +** the target type. | |
| 29 | +** | |
| 30 | +** zTarget is an attachment target name: wiki page name, tech-note ID, | |
| 31 | +** ticket ID, or forumpost hash. | |
| 32 | +** | |
| 33 | +** If bFull is true then it requires zTarget to be a full ID for | |
| 34 | +** tech-notes and tickets, otherwise such IDs may be prefixes. If | |
| 35 | +** bFull is false then tech-notes and tickets will perform a prefix | |
| 36 | +** match, but it is up to the caller to provide enough of a prefix to | |
| 37 | +** rule out a collision[^1]. When called repeatedly, this routine can | |
| 38 | +** run a bit faster and more efficiently if bFull is true, but some | |
| 39 | +** historical use cases call for prefix matches. | |
| 40 | +** | |
| 41 | +** Wiki page names always require an exact match. | |
| 42 | +** | |
| 43 | +** Forum posts are a special case: | |
| 44 | +** | |
| 45 | +** - The ignore the bFull flag. That is, they will do prefix matches | |
| 46 | +** but will not match an ambiguous prefix. | |
| 47 | +** | |
| 48 | +** - It is up to the caller to, if needed, resolve zTarget using | |
| 49 | +** forumpost_head_rid2() to resolve the RID of the earliest version | |
| 50 | +** of the post, as that is the only one which attachments should | |
| 51 | +** target. | |
| 52 | +** | |
| 53 | +** [^1]: Historically (from the perspective of 2026-06) attachment | |
| 54 | +** target lookups have used GLOB prefix matching but have taken no | |
| 55 | +** measures to ensure that the prefix is unambiguous. Ergo we don't | |
| 56 | +** here, either. It is assumed that the caller passes enough of a | |
| 57 | +** prefix to be unambiguous and that's worked out fine so far. | |
| 49 | 58 | */ |
| 50 | 59 | int attachment_target_type(const char *zTarget, int bFull){ |
| 51 | 60 | if( !zTarget || !zTarget[0] || strlen(zTarget)>64/*vs. abuse*/ ){ |
| 52 | 61 | return 0; |
| 53 | 62 | } |
| @@ -95,14 +104,14 @@ | ||
| 95 | 104 | } |
| 96 | 105 | } |
| 97 | 106 | |
| 98 | 107 | /* |
| 99 | 108 | ** Given an attachment target name, returns the target's blob.rid. |
| 100 | -** zTarget must be a full wiki page name, tech-note ID, ticket ID, or | |
| 101 | -** forum post hash. Returns 0 if no match is found. | |
| 109 | +** zTarget and bFull work as described for attachment_target_type(). | |
| 102 | 110 | ** |
| 103 | -** bFull is interpreted as per attachment_target_type(). | |
| 111 | +** For forum posts, this always returns the RID of the first version | |
| 112 | +** of the post, as attachments should always target that instance. | |
| 104 | 113 | */ |
| 105 | 114 | int attachment_target_rid(const char *zTarget, int bFull){ |
| 106 | 115 | int rid = 0; |
| 107 | 116 | const int eType = attachment_target_type(zTarget, bFull); |
| 108 | 117 | switch(eType){ |
| @@ -1660,67 +1669,68 @@ | ||
| 1660 | 1669 | const char *zTarget = g.argv[i]; |
| 1661 | 1670 | const int rid = attachment_target_rid(zTarget, 0); |
| 1662 | 1671 | const int type = attachment_target_type(zTarget, 0); |
| 1663 | 1672 | const char *zType = "<invalid>"; |
| 1664 | 1673 | switch(type){ |
| 1665 | - case CFTYPE_EVENT: zType = "e"; break; | |
| 1666 | - case CFTYPE_FORUM: zType = "f"; break; | |
| 1667 | - case CFTYPE_TICKET: zType = "t"; break; | |
| 1668 | - case CFTYPE_WIKI: zType = "w"; break; | |
| 1674 | + case CFTYPE_EVENT: zType = "technote"; break; | |
| 1675 | + case CFTYPE_FORUM: zType = "forumpost"; break; | |
| 1676 | + case CFTYPE_TICKET: zType = "ticket"; break; | |
| 1677 | + case CFTYPE_WIKI: zType = "wiki"; break; | |
| 1669 | 1678 | } |
| 1670 | - fossil_print("%-20s = %s %d %z\n", | |
| 1679 | + fossil_print("%-20s = %-9s #%d %z\n", | |
| 1671 | 1680 | zTarget, zType, rid, |
| 1672 | 1681 | rid>0 ? rid_to_uuid(rid) : 0); |
| 1673 | 1682 | } |
| 1674 | 1683 | } |
| 1675 | 1684 | |
| 1676 | 1685 | |
| 1677 | 1686 | /* |
| 1678 | 1687 | ** COMMAND: test-attachments-to-json |
| 1679 | 1688 | ** |
| 1680 | -** Usage: %fossil test-attachments-to-json TARGET_ID | |
| 1689 | +** Usage: %fossil test-attachments-to-json TARGET_ID... | |
| 1681 | 1690 | ** |
| 1682 | 1691 | ** Options: |
| 1683 | 1692 | ** --old List all versions of attachments. Default is to |
| 1684 | 1693 | ** list only the latest. |
| 1685 | 1694 | ** --full Require a full target ID, not a prefix. |
| 1686 | 1695 | ** |
| 1687 | -** Emits a JSON array of attachments for the given attachment target. | |
| 1688 | -** The given ID must be a wiki page name, ticket hash, tech-note hash, | |
| 1689 | -** or forum post hash. By default it accepts prefixes but does not | |
| 1690 | -** detection of ambiguity or cross-type prefix collisions so may emit | |
| 1691 | -** curious results if given short/colliding IDs. | |
| 1696 | +** Emits a JSON array of attachments for the given attachment targets. | |
| 1697 | +** The given IDs must be wiki page names, ticket hashes, tech-note | |
| 1698 | +** hashes, or forum post hashes. By default it accepts hash prefixes | |
| 1699 | +** but does no detection of ambiguity or cross-type prefix collisions | |
| 1700 | +** so may emit curious results if given short, colliding IDs. | |
| 1692 | 1701 | */ |
| 1693 | 1702 | void test_attachments_to_json_cmd(void){ |
| 1694 | - Manifest *pManifest; | |
| 1695 | - Blob b = BLOB_INITIALIZER; | |
| 1696 | - int bLatestOnly = find_option("old",0,0)==0; | |
| 1697 | - int emptyPolicy = 1; | |
| 1698 | - int rid, i; | |
| 1699 | - int bFullId = find_option("full",0,0)!=0; | |
| 1703 | + const int emptyPolicy = 1; | |
| 1704 | + const int bLatestOnly = find_option("old",0,0)==0; | |
| 1705 | + const int bFullId = find_option("full",0,0)!=0; | |
| 1706 | + int i; | |
| 1707 | + | |
| 1700 | 1708 | verify_all_options(); |
| 1701 | 1709 | db_find_and_open_repository(0, 0); |
| 1702 | 1710 | if( g.argc<3 ){ |
| 1703 | 1711 | usage("test-attachments-to-json TARGET_ID"); |
| 1704 | 1712 | return; |
| 1705 | 1713 | } |
| 1706 | 1714 | for( i = 2; i < g.argc; ++i ){ |
| 1707 | 1715 | const char *zTarget = g.argv[i]; |
| 1708 | - rid = attachment_target_rid(zTarget, bFullId); | |
| 1716 | + const int rid = attachment_target_rid(zTarget, bFullId); | |
| 1709 | 1717 | if( 0==rid ){ |
| 1710 | 1718 | fossil_print("** cannot resolve %s\n", zTarget); |
| 1711 | - continue; | |
| 1712 | - } | |
| 1713 | - pManifest = manifest_get(rid, CFTYPE_ANY, NULL); | |
| 1714 | - attachments_to_json(pManifest, &b, bLatestOnly, emptyPolicy); | |
| 1715 | - fossil_print("Attachments for %s: ", zTarget); | |
| 1716 | - if( b.nUsed ){ | |
| 1717 | - char *zPretty = db_text(0,"SELECT json_pretty(%B)", &b); | |
| 1718 | - fossil_print("%s\n", zPretty); | |
| 1719 | - fossil_free(zPretty); | |
| 1720 | 1719 | }else{ |
| 1721 | - fossil_print("none\n"); | |
| 1720 | + Blob b = BLOB_INITIALIZER; | |
| 1721 | + Manifest *pManifest = manifest_get(rid, CFTYPE_ANY, NULL); | |
| 1722 | + assert( pManifest ); | |
| 1723 | + attachments_to_json(pManifest, &b, bLatestOnly, emptyPolicy); | |
| 1724 | + fossil_print("Attachments for %s: ", zTarget); | |
| 1725 | + if( b.nUsed ){ | |
| 1726 | + char *zPretty = db_text(0,"SELECT json_pretty(%B)", &b); | |
| 1727 | + fossil_print("%s\n", zPretty); | |
| 1728 | + fossil_free(zPretty); | |
| 1729 | + }else{ | |
| 1730 | + fossil_print("none\n"); | |
| 1731 | + } | |
| 1732 | + blob_reset(&b); | |
| 1733 | + manifest_destroy(pManifest); | |
| 1722 | 1734 | } |
| 1723 | - blob_reset(&b); | |
| 1724 | - manifest_destroy(pManifest); | |
| 1725 | 1735 | } |
| 1726 | 1736 | } |
| 1727 | 1737 |
| --- src/attach.c | |
| +++ src/attach.c | |
| @@ -22,32 +22,41 @@ | |
| 22 | #include <assert.h> |
| 23 | |
| 24 | /* |
| 25 | ** Given a presumedly legal attachment target name, this guesses the |
| 26 | ** target type and returns one of CFTYPE_FORUM, CFTYPE_WIKI, |
| 27 | ** CFTYPE_TICKET, or CFTYPE_EVENT. Returns 0 if it cannot |
| 28 | ** distinguish the target type. |
| 29 | ** |
| 30 | ** If bFull is true then it requires zTarget to be an exact matches |
| 31 | ** for wiki, tech-note, and ticket IDs. If bFull is false then |
| 32 | ** tech-notes and tickets will perform a prefix match, but it is up to |
| 33 | ** the caller to provide enough of a prefix to rule out a |
| 34 | ** collision[^1]. Forum posts are a special case and ignore the bFull |
| 35 | ** flag. When called repeatedly, this routine can run a bit faster and |
| 36 | ** more efficiently if bFull is true, but some historical use cases |
| 37 | ** call for prefix matches. |
| 38 | ** |
| 39 | ** In the case of CFTYPE_FORUM, it is up to the caller to ensure that, |
| 40 | ** if needed, they resolve zTarget using forumpost_head_rid2() so that |
| 41 | ** they get the RID of the earliest version of the post, as that is |
| 42 | ** the only one which attachments should target. |
| 43 | ** |
| 44 | ** [^1]: Historically (as of 2026-06) attachment target lookups have |
| 45 | ** used GLOB prefix matching but taken no measures to ensure that the |
| 46 | ** prefix is unambiguous. Ergo we don't here, either. It is assumed |
| 47 | ** that the caller passes enough of a prefix to be unambiguous and |
| 48 | ** that's worked out fine so far. |
| 49 | */ |
| 50 | int attachment_target_type(const char *zTarget, int bFull){ |
| 51 | if( !zTarget || !zTarget[0] || strlen(zTarget)>64/*vs. abuse*/ ){ |
| 52 | return 0; |
| 53 | } |
| @@ -95,14 +104,14 @@ | |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | /* |
| 99 | ** Given an attachment target name, returns the target's blob.rid. |
| 100 | ** zTarget must be a full wiki page name, tech-note ID, ticket ID, or |
| 101 | ** forum post hash. Returns 0 if no match is found. |
| 102 | ** |
| 103 | ** bFull is interpreted as per attachment_target_type(). |
| 104 | */ |
| 105 | int attachment_target_rid(const char *zTarget, int bFull){ |
| 106 | int rid = 0; |
| 107 | const int eType = attachment_target_type(zTarget, bFull); |
| 108 | switch(eType){ |
| @@ -1660,67 +1669,68 @@ | |
| 1660 | const char *zTarget = g.argv[i]; |
| 1661 | const int rid = attachment_target_rid(zTarget, 0); |
| 1662 | const int type = attachment_target_type(zTarget, 0); |
| 1663 | const char *zType = "<invalid>"; |
| 1664 | switch(type){ |
| 1665 | case CFTYPE_EVENT: zType = "e"; break; |
| 1666 | case CFTYPE_FORUM: zType = "f"; break; |
| 1667 | case CFTYPE_TICKET: zType = "t"; break; |
| 1668 | case CFTYPE_WIKI: zType = "w"; break; |
| 1669 | } |
| 1670 | fossil_print("%-20s = %s %d %z\n", |
| 1671 | zTarget, zType, rid, |
| 1672 | rid>0 ? rid_to_uuid(rid) : 0); |
| 1673 | } |
| 1674 | } |
| 1675 | |
| 1676 | |
| 1677 | /* |
| 1678 | ** COMMAND: test-attachments-to-json |
| 1679 | ** |
| 1680 | ** Usage: %fossil test-attachments-to-json TARGET_ID |
| 1681 | ** |
| 1682 | ** Options: |
| 1683 | ** --old List all versions of attachments. Default is to |
| 1684 | ** list only the latest. |
| 1685 | ** --full Require a full target ID, not a prefix. |
| 1686 | ** |
| 1687 | ** Emits a JSON array of attachments for the given attachment target. |
| 1688 | ** The given ID must be a wiki page name, ticket hash, tech-note hash, |
| 1689 | ** or forum post hash. By default it accepts prefixes but does not |
| 1690 | ** detection of ambiguity or cross-type prefix collisions so may emit |
| 1691 | ** curious results if given short/colliding IDs. |
| 1692 | */ |
| 1693 | void test_attachments_to_json_cmd(void){ |
| 1694 | Manifest *pManifest; |
| 1695 | Blob b = BLOB_INITIALIZER; |
| 1696 | int bLatestOnly = find_option("old",0,0)==0; |
| 1697 | int emptyPolicy = 1; |
| 1698 | int rid, i; |
| 1699 | int bFullId = find_option("full",0,0)!=0; |
| 1700 | verify_all_options(); |
| 1701 | db_find_and_open_repository(0, 0); |
| 1702 | if( g.argc<3 ){ |
| 1703 | usage("test-attachments-to-json TARGET_ID"); |
| 1704 | return; |
| 1705 | } |
| 1706 | for( i = 2; i < g.argc; ++i ){ |
| 1707 | const char *zTarget = g.argv[i]; |
| 1708 | rid = attachment_target_rid(zTarget, bFullId); |
| 1709 | if( 0==rid ){ |
| 1710 | fossil_print("** cannot resolve %s\n", zTarget); |
| 1711 | continue; |
| 1712 | } |
| 1713 | pManifest = manifest_get(rid, CFTYPE_ANY, NULL); |
| 1714 | attachments_to_json(pManifest, &b, bLatestOnly, emptyPolicy); |
| 1715 | fossil_print("Attachments for %s: ", zTarget); |
| 1716 | if( b.nUsed ){ |
| 1717 | char *zPretty = db_text(0,"SELECT json_pretty(%B)", &b); |
| 1718 | fossil_print("%s\n", zPretty); |
| 1719 | fossil_free(zPretty); |
| 1720 | }else{ |
| 1721 | fossil_print("none\n"); |
| 1722 | } |
| 1723 | blob_reset(&b); |
| 1724 | manifest_destroy(pManifest); |
| 1725 | } |
| 1726 | } |
| 1727 |
| --- src/attach.c | |
| +++ src/attach.c | |
| @@ -22,32 +22,41 @@ | |
| 22 | #include <assert.h> |
| 23 | |
| 24 | /* |
| 25 | ** Given a presumedly legal attachment target name, this guesses the |
| 26 | ** target type and returns one of CFTYPE_FORUM, CFTYPE_WIKI, |
| 27 | ** CFTYPE_TICKET, or CFTYPE_EVENT. Returns 0 if it cannot distinguish |
| 28 | ** the target type. |
| 29 | ** |
| 30 | ** zTarget is an attachment target name: wiki page name, tech-note ID, |
| 31 | ** ticket ID, or forumpost hash. |
| 32 | ** |
| 33 | ** If bFull is true then it requires zTarget to be a full ID for |
| 34 | ** tech-notes and tickets, otherwise such IDs may be prefixes. If |
| 35 | ** bFull is false then tech-notes and tickets will perform a prefix |
| 36 | ** match, but it is up to the caller to provide enough of a prefix to |
| 37 | ** rule out a collision[^1]. When called repeatedly, this routine can |
| 38 | ** run a bit faster and more efficiently if bFull is true, but some |
| 39 | ** historical use cases call for prefix matches. |
| 40 | ** |
| 41 | ** Wiki page names always require an exact match. |
| 42 | ** |
| 43 | ** Forum posts are a special case: |
| 44 | ** |
| 45 | ** - The ignore the bFull flag. That is, they will do prefix matches |
| 46 | ** but will not match an ambiguous prefix. |
| 47 | ** |
| 48 | ** - It is up to the caller to, if needed, resolve zTarget using |
| 49 | ** forumpost_head_rid2() to resolve the RID of the earliest version |
| 50 | ** of the post, as that is the only one which attachments should |
| 51 | ** target. |
| 52 | ** |
| 53 | ** [^1]: Historically (from the perspective of 2026-06) attachment |
| 54 | ** target lookups have used GLOB prefix matching but have taken no |
| 55 | ** measures to ensure that the prefix is unambiguous. Ergo we don't |
| 56 | ** here, either. It is assumed that the caller passes enough of a |
| 57 | ** prefix to be unambiguous and that's worked out fine so far. |
| 58 | */ |
| 59 | int attachment_target_type(const char *zTarget, int bFull){ |
| 60 | if( !zTarget || !zTarget[0] || strlen(zTarget)>64/*vs. abuse*/ ){ |
| 61 | return 0; |
| 62 | } |
| @@ -95,14 +104,14 @@ | |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | /* |
| 108 | ** Given an attachment target name, returns the target's blob.rid. |
| 109 | ** zTarget and bFull work as described for attachment_target_type(). |
| 110 | ** |
| 111 | ** For forum posts, this always returns the RID of the first version |
| 112 | ** of the post, as attachments should always target that instance. |
| 113 | */ |
| 114 | int attachment_target_rid(const char *zTarget, int bFull){ |
| 115 | int rid = 0; |
| 116 | const int eType = attachment_target_type(zTarget, bFull); |
| 117 | switch(eType){ |
| @@ -1660,67 +1669,68 @@ | |
| 1669 | const char *zTarget = g.argv[i]; |
| 1670 | const int rid = attachment_target_rid(zTarget, 0); |
| 1671 | const int type = attachment_target_type(zTarget, 0); |
| 1672 | const char *zType = "<invalid>"; |
| 1673 | switch(type){ |
| 1674 | case CFTYPE_EVENT: zType = "technote"; break; |
| 1675 | case CFTYPE_FORUM: zType = "forumpost"; break; |
| 1676 | case CFTYPE_TICKET: zType = "ticket"; break; |
| 1677 | case CFTYPE_WIKI: zType = "wiki"; break; |
| 1678 | } |
| 1679 | fossil_print("%-20s = %-9s #%d %z\n", |
| 1680 | zTarget, zType, rid, |
| 1681 | rid>0 ? rid_to_uuid(rid) : 0); |
| 1682 | } |
| 1683 | } |
| 1684 | |
| 1685 | |
| 1686 | /* |
| 1687 | ** COMMAND: test-attachments-to-json |
| 1688 | ** |
| 1689 | ** Usage: %fossil test-attachments-to-json TARGET_ID... |
| 1690 | ** |
| 1691 | ** Options: |
| 1692 | ** --old List all versions of attachments. Default is to |
| 1693 | ** list only the latest. |
| 1694 | ** --full Require a full target ID, not a prefix. |
| 1695 | ** |
| 1696 | ** Emits a JSON array of attachments for the given attachment targets. |
| 1697 | ** The given IDs must be wiki page names, ticket hashes, tech-note |
| 1698 | ** hashes, or forum post hashes. By default it accepts hash prefixes |
| 1699 | ** but does no detection of ambiguity or cross-type prefix collisions |
| 1700 | ** so may emit curious results if given short, colliding IDs. |
| 1701 | */ |
| 1702 | void test_attachments_to_json_cmd(void){ |
| 1703 | const int emptyPolicy = 1; |
| 1704 | const int bLatestOnly = find_option("old",0,0)==0; |
| 1705 | const int bFullId = find_option("full",0,0)!=0; |
| 1706 | int i; |
| 1707 | |
| 1708 | verify_all_options(); |
| 1709 | db_find_and_open_repository(0, 0); |
| 1710 | if( g.argc<3 ){ |
| 1711 | usage("test-attachments-to-json TARGET_ID"); |
| 1712 | return; |
| 1713 | } |
| 1714 | for( i = 2; i < g.argc; ++i ){ |
| 1715 | const char *zTarget = g.argv[i]; |
| 1716 | const int rid = attachment_target_rid(zTarget, bFullId); |
| 1717 | if( 0==rid ){ |
| 1718 | fossil_print("** cannot resolve %s\n", zTarget); |
| 1719 | }else{ |
| 1720 | Blob b = BLOB_INITIALIZER; |
| 1721 | Manifest *pManifest = manifest_get(rid, CFTYPE_ANY, NULL); |
| 1722 | assert( pManifest ); |
| 1723 | attachments_to_json(pManifest, &b, bLatestOnly, emptyPolicy); |
| 1724 | fossil_print("Attachments for %s: ", zTarget); |
| 1725 | if( b.nUsed ){ |
| 1726 | char *zPretty = db_text(0,"SELECT json_pretty(%B)", &b); |
| 1727 | fossil_print("%s\n", zPretty); |
| 1728 | fossil_free(zPretty); |
| 1729 | }else{ |
| 1730 | fossil_print("none\n"); |
| 1731 | } |
| 1732 | blob_reset(&b); |
| 1733 | manifest_destroy(pManifest); |
| 1734 | } |
| 1735 | } |
| 1736 | } |
| 1737 |