diff options
author | Luca Muscariello <lumuscar+fdio@cisco.com> | 2017-02-23 20:44:26 +0100 |
---|---|---|
committer | Luca Muscariello <lumuscar+fdio@cisco.com> | 2017-02-23 19:51:14 +0000 |
commit | d18ae43123fcd7604d1c36a1ec8450dbe6071824 (patch) | |
tree | 2d49fc3aabd0f2607251c854565648d47b56b2e9 /libccnx-common/ccnx/common/test | |
parent | 9b30fc10fb1cbebe651e5a107e8ca5b24de54675 (diff) |
Initial commit: ccnxlibs.
Change-Id: I1b376527a7dd01a6b9e083a6cb646955902f45c0
Signed-off-by: Luca Muscariello <lumuscar+fdio@cisco.com>
Diffstat (limited to 'libccnx-common/ccnx/common/test')
19 files changed, 9640 insertions, 0 deletions
diff --git a/libccnx-common/ccnx/common/test/.gitignore b/libccnx-common/ccnx/common/test/.gitignore new file mode 100644 index 00000000..dc9b70b3 --- /dev/null +++ b/libccnx-common/ccnx/common/test/.gitignore @@ -0,0 +1,22 @@ +./Makefile.am +./Makefile.in +test_ccnx_BufferChunker +test_ccnx_FileChunker +test_ccnx_Chunker +test_ccnx_ContentObject +test_ccnx_Interest +test_ccnx_Json +test_ccnx_Key +test_ccnx_KeyListEntry +test_ccnx_KeyLocator +test_ccnx_Link +test_ccnx_Manifest +test_ccnx_ManifestSection +test_ccnx_Name +test_ccnx_NameLabel +test_ccnx_NameSegment +test_ccnx_NameSegmentNumber +test_ccnx_NameType +test_ccnx_NetworkBuffer +test_ccnx_TimeStamp +test_ccnx_WireFormatMessage diff --git a/libccnx-common/ccnx/common/test/CMakeLists.txt b/libccnx-common/ccnx/common/test/CMakeLists.txt new file mode 100644 index 00000000..4cf70a14 --- /dev/null +++ b/libccnx-common/ccnx/common/test/CMakeLists.txt @@ -0,0 +1,29 @@ +# Enable gcov output for the tests +add_definitions(--coverage) +set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage") + +configure_file(data.json data.json COPYONLY) + +set(TestsExpectedToPass + test_ccnx_ContentObject + test_ccnx_Interest + test_ccnx_InterestPayloadId + test_ccnx_InterestReturn + test_ccnx_KeyLocator + test_ccnx_KeystoreUtilities + test_ccnx_Link + test_ccnx_Manifest + test_ccnx_ManifestHashGroup + test_ccnx_Name + test_ccnx_NameLabel + test_ccnx_NameSegment + test_ccnx_NameSegmentNumber + test_ccnx_TimeStamp + test_ccnx_WireFormatMessage +) + + +foreach(test ${TestsExpectedToPass}) + AddTest(${test}) +endforeach() + diff --git a/libccnx-common/ccnx/common/test/data.json b/libccnx-common/ccnx/common/test/data.json new file mode 100644 index 00000000..a146f6ff --- /dev/null +++ b/libccnx-common/ccnx/common/test/data.json @@ -0,0 +1,2614 @@ +{ + "array" : [ + { + "id": 6104546, + "name": "-REPONAME", + "full_name": "mralexgray/-REPONAME", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/-REPONAME", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/mralexgray/-REPONAME", + "forks_url": "https://api.github.com/repos/mralexgray/-REPONAME/forks", + "keys_url": "https://api.github.com/repos/mralexgray/-REPONAME/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/-REPONAME/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/-REPONAME/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/-REPONAME/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/-REPONAME/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/-REPONAME/events", + "assignees_url": "https://api.github.com/repos/mralexgray/-REPONAME/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/-REPONAME/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/-REPONAME/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/-REPONAME/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/-REPONAME/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/-REPONAME/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/-REPONAME/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/-REPONAME/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/-REPONAME/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/-REPONAME/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/-REPONAME/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/-REPONAME/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/-REPONAME/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/-REPONAME/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/-REPONAME/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/-REPONAME/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/-REPONAME/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/-REPONAME/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/-REPONAME/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/-REPONAME/merges", + "archive_url": "https://api.github.com/repos/mralexgray/-REPONAME/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/-REPONAME/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/-REPONAME/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/-REPONAME/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/-REPONAME/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/-REPONAME/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/-REPONAME/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/-REPONAME/releases{/id}", + "created_at": "2012-10-06T16:37:39Z", + "updated_at": "2013-01-12T13:39:30Z", + "pushed_at": "2012-10-06T16:37:39Z", + "git_url": "git://github.com/mralexgray/-REPONAME.git", + "ssh_url": "git@github.com:mralexgray/-REPONAME.git", + "clone_url": "https://github.com/mralexgray/-REPONAME.git", + "svn_url": "https://github.com/mralexgray/-REPONAME", + "homepage": null, + "size": 48, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 13121042, + "name": "ace", + "full_name": "mralexgray/ace", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/ace", + "description": "Ace (Ajax.org Cloud9 Editor)", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/ace", + "forks_url": "https://api.github.com/repos/mralexgray/ace/forks", + "keys_url": "https://api.github.com/repos/mralexgray/ace/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/ace/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/ace/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/ace/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/ace/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/ace/events", + "assignees_url": "https://api.github.com/repos/mralexgray/ace/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/ace/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/ace/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/ace/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/ace/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/ace/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/ace/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/ace/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/ace/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/ace/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/ace/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/ace/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/ace/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/ace/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/ace/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/ace/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/ace/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/ace/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/ace/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/ace/merges", + "archive_url": "https://api.github.com/repos/mralexgray/ace/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/ace/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/ace/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/ace/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/ace/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/ace/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/ace/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/ace/releases{/id}", + "created_at": "2013-09-26T11:58:10Z", + "updated_at": "2013-10-26T12:34:49Z", + "pushed_at": "2013-10-26T12:34:48Z", + "git_url": "git://github.com/mralexgray/ace.git", + "ssh_url": "git@github.com:mralexgray/ace.git", + "clone_url": "https://github.com/mralexgray/ace.git", + "svn_url": "https://github.com/mralexgray/ace", + "homepage": "http://ace.c9.io", + "size": 21080, + "stargazers_count": 0, + "watchers_count": 0, + "language": "JavaScript", + "has_issues": false, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 10791045, + "name": "ACEView", + "full_name": "mralexgray/ACEView", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/ACEView", + "description": "Use the wonderful ACE editor in your Cocoa applications", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/ACEView", + "forks_url": "https://api.github.com/repos/mralexgray/ACEView/forks", + "keys_url": "https://api.github.com/repos/mralexgray/ACEView/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/ACEView/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/ACEView/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/ACEView/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/ACEView/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/ACEView/events", + "assignees_url": "https://api.github.com/repos/mralexgray/ACEView/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/ACEView/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/ACEView/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/ACEView/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/ACEView/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/ACEView/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/ACEView/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/ACEView/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/ACEView/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/ACEView/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/ACEView/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/ACEView/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/ACEView/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/ACEView/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/ACEView/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/ACEView/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/ACEView/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/ACEView/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/ACEView/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/ACEView/merges", + "archive_url": "https://api.github.com/repos/mralexgray/ACEView/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/ACEView/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/ACEView/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/ACEView/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/ACEView/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/ACEView/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/ACEView/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/ACEView/releases{/id}", + "created_at": "2013-06-19T12:15:04Z", + "updated_at": "2013-10-30T12:39:24Z", + "pushed_at": "2013-10-30T12:39:18Z", + "git_url": "git://github.com/mralexgray/ACEView.git", + "ssh_url": "git@github.com:mralexgray/ACEView.git", + "clone_url": "https://github.com/mralexgray/ACEView.git", + "svn_url": "https://github.com/mralexgray/ACEView", + "homepage": null, + "size": 1661, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Objective-C", + "has_issues": false, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 13623648, + "name": "ActiveLog", + "full_name": "mralexgray/ActiveLog", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/ActiveLog", + "description": "Shut up all logs with active filter.", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/ActiveLog", + "forks_url": "https://api.github.com/repos/mralexgray/ActiveLog/forks", + "keys_url": "https://api.github.com/repos/mralexgray/ActiveLog/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/ActiveLog/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/ActiveLog/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/ActiveLog/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/ActiveLog/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/ActiveLog/events", + "assignees_url": "https://api.github.com/repos/mralexgray/ActiveLog/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/ActiveLog/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/ActiveLog/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/ActiveLog/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/ActiveLog/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/ActiveLog/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/ActiveLog/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/ActiveLog/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/ActiveLog/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/ActiveLog/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/ActiveLog/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/ActiveLog/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/ActiveLog/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/ActiveLog/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/ActiveLog/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/ActiveLog/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/ActiveLog/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/ActiveLog/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/ActiveLog/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/ActiveLog/merges", + "archive_url": "https://api.github.com/repos/mralexgray/ActiveLog/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/ActiveLog/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/ActiveLog/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/ActiveLog/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/ActiveLog/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/ActiveLog/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/ActiveLog/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/ActiveLog/releases{/id}", + "created_at": "2013-10-16T15:52:37Z", + "updated_at": "2013-10-16T15:52:37Z", + "pushed_at": "2011-07-03T06:28:59Z", + "git_url": "git://github.com/mralexgray/ActiveLog.git", + "ssh_url": "git@github.com:mralexgray/ActiveLog.git", + "clone_url": "https://github.com/mralexgray/ActiveLog.git", + "svn_url": "https://github.com/mralexgray/ActiveLog", + "homepage": "http://deepitpro.com/en/articles/ActiveLog/info/", + "size": 60, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Objective-C", + "has_issues": false, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 9716210, + "name": "adium", + "full_name": "mralexgray/adium", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/adium", + "description": "Official mirror of hg.adium.im", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/adium", + "forks_url": "https://api.github.com/repos/mralexgray/adium/forks", + "keys_url": "https://api.github.com/repos/mralexgray/adium/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/adium/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/adium/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/adium/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/adium/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/adium/events", + "assignees_url": "https://api.github.com/repos/mralexgray/adium/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/adium/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/adium/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/adium/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/adium/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/adium/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/adium/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/adium/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/adium/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/adium/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/adium/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/adium/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/adium/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/adium/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/adium/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/adium/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/adium/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/adium/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/adium/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/adium/merges", + "archive_url": "https://api.github.com/repos/mralexgray/adium/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/adium/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/adium/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/adium/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/adium/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/adium/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/adium/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/adium/releases{/id}", + "created_at": "2013-04-27T14:59:33Z", + "updated_at": "2013-04-27T14:59:33Z", + "pushed_at": "2013-04-26T16:43:53Z", + "git_url": "git://github.com/mralexgray/adium.git", + "ssh_url": "git@github.com:mralexgray/adium.git", + "clone_url": "https://github.com/mralexgray/adium.git", + "svn_url": "https://github.com/mralexgray/adium", + "homepage": null, + "size": 277719, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Objective-C", + "has_issues": false, + "has_downloads": true, + "has_wiki": false, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 12752329, + "name": "ADLivelyTableView", + "full_name": "mralexgray/ADLivelyTableView", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/ADLivelyTableView", + "description": "Lively UITableView", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/ADLivelyTableView", + "forks_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/forks", + "keys_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/events", + "assignees_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/merges", + "archive_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/ADLivelyTableView/releases{/id}", + "created_at": "2013-09-11T09:18:01Z", + "updated_at": "2013-09-11T09:18:03Z", + "pushed_at": "2012-05-10T10:40:15Z", + "git_url": "git://github.com/mralexgray/ADLivelyTableView.git", + "ssh_url": "git@github.com:mralexgray/ADLivelyTableView.git", + "clone_url": "https://github.com/mralexgray/ADLivelyTableView.git", + "svn_url": "https://github.com/mralexgray/ADLivelyTableView", + "homepage": "http://applidium.com/en/news/lively_uitableview/", + "size": 73, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Objective-C", + "has_issues": false, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 5697379, + "name": "AFIncrementalStore", + "full_name": "mralexgray/AFIncrementalStore", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/AFIncrementalStore", + "description": "Core Data Persistence with AFNetworking, Done Right", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/AFIncrementalStore", + "forks_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/forks", + "keys_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/events", + "assignees_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/merges", + "archive_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/AFIncrementalStore/releases{/id}", + "created_at": "2012-09-06T04:20:33Z", + "updated_at": "2013-01-12T03:15:29Z", + "pushed_at": "2012-09-01T22:46:25Z", + "git_url": "git://github.com/mralexgray/AFIncrementalStore.git", + "ssh_url": "git@github.com:mralexgray/AFIncrementalStore.git", + "clone_url": "https://github.com/mralexgray/AFIncrementalStore.git", + "svn_url": "https://github.com/mralexgray/AFIncrementalStore", + "homepage": null, + "size": 139, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Objective-C", + "has_issues": false, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 6969621, + "name": "AFNetworking", + "full_name": "mralexgray/AFNetworking", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/AFNetworking", + "description": "A delightful iOS and OS X networking framework", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/AFNetworking", + "forks_url": "https://api.github.com/repos/mralexgray/AFNetworking/forks", + "keys_url": "https://api.github.com/repos/mralexgray/AFNetworking/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/AFNetworking/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/AFNetworking/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/AFNetworking/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/AFNetworking/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/AFNetworking/events", + "assignees_url": "https://api.github.com/repos/mralexgray/AFNetworking/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/AFNetworking/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/AFNetworking/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/AFNetworking/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/AFNetworking/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/AFNetworking/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/AFNetworking/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/AFNetworking/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/AFNetworking/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/AFNetworking/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/AFNetworking/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/AFNetworking/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/AFNetworking/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/AFNetworking/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/AFNetworking/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/AFNetworking/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/AFNetworking/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/AFNetworking/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/AFNetworking/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/AFNetworking/merges", + "archive_url": "https://api.github.com/repos/mralexgray/AFNetworking/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/AFNetworking/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/AFNetworking/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/AFNetworking/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/AFNetworking/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/AFNetworking/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/AFNetworking/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/AFNetworking/releases{/id}", + "created_at": "2012-12-02T17:00:04Z", + "updated_at": "2014-01-24T07:14:33Z", + "pushed_at": "2014-01-24T07:14:32Z", + "git_url": "git://github.com/mralexgray/AFNetworking.git", + "ssh_url": "git@github.com:mralexgray/AFNetworking.git", + "clone_url": "https://github.com/mralexgray/AFNetworking.git", + "svn_url": "https://github.com/mralexgray/AFNetworking", + "homepage": "http://afnetworking.com", + "size": 4341, + "stargazers_count": 1, + "watchers_count": 1, + "language": "Objective-C", + "has_issues": false, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 1, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 9485541, + "name": "AGNSSplitView", + "full_name": "mralexgray/AGNSSplitView", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/AGNSSplitView", + "description": "Simple NSSplitView additions.", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/AGNSSplitView", + "forks_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/forks", + "keys_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/events", + "assignees_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/merges", + "archive_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/AGNSSplitView/releases{/id}", + "created_at": "2013-04-17T00:10:13Z", + "updated_at": "2013-04-17T00:10:13Z", + "pushed_at": "2013-02-26T00:32:32Z", + "git_url": "git://github.com/mralexgray/AGNSSplitView.git", + "ssh_url": "git@github.com:mralexgray/AGNSSplitView.git", + "clone_url": "https://github.com/mralexgray/AGNSSplitView.git", + "svn_url": "https://github.com/mralexgray/AGNSSplitView", + "homepage": null, + "size": 68, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Objective-C", + "has_issues": false, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 12767784, + "name": "AGScopeBar", + "full_name": "mralexgray/AGScopeBar", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/AGScopeBar", + "description": "Custom scope bar implementation for Cocoa", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/AGScopeBar", + "forks_url": "https://api.github.com/repos/mralexgray/AGScopeBar/forks", + "keys_url": "https://api.github.com/repos/mralexgray/AGScopeBar/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/AGScopeBar/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/AGScopeBar/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/AGScopeBar/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/AGScopeBar/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/AGScopeBar/events", + "assignees_url": "https://api.github.com/repos/mralexgray/AGScopeBar/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/AGScopeBar/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/AGScopeBar/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/AGScopeBar/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/AGScopeBar/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/AGScopeBar/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/AGScopeBar/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/AGScopeBar/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/AGScopeBar/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/AGScopeBar/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/AGScopeBar/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/AGScopeBar/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/AGScopeBar/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/AGScopeBar/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/AGScopeBar/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/AGScopeBar/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/AGScopeBar/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/AGScopeBar/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/AGScopeBar/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/AGScopeBar/merges", + "archive_url": "https://api.github.com/repos/mralexgray/AGScopeBar/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/AGScopeBar/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/AGScopeBar/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/AGScopeBar/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/AGScopeBar/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/AGScopeBar/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/AGScopeBar/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/AGScopeBar/releases{/id}", + "created_at": "2013-09-11T21:06:54Z", + "updated_at": "2013-09-11T21:06:54Z", + "pushed_at": "2013-05-07T03:35:29Z", + "git_url": "git://github.com/mralexgray/AGScopeBar.git", + "ssh_url": "git@github.com:mralexgray/AGScopeBar.git", + "clone_url": "https://github.com/mralexgray/AGScopeBar.git", + "svn_url": "https://github.com/mralexgray/AGScopeBar", + "homepage": null, + "size": 64, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Objective-C", + "has_issues": false, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 9227846, + "name": "AHContentBrowser", + "full_name": "mralexgray/AHContentBrowser", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/AHContentBrowser", + "description": "A Mac only webview that loads a fast readable version of the website if available.", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/AHContentBrowser", + "forks_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/forks", + "keys_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/events", + "assignees_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/merges", + "archive_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/AHContentBrowser/releases{/id}", + "created_at": "2013-04-04T20:56:16Z", + "updated_at": "2013-04-04T20:56:16Z", + "pushed_at": "2013-03-13T17:38:23Z", + "git_url": "git://github.com/mralexgray/AHContentBrowser.git", + "ssh_url": "git@github.com:mralexgray/AHContentBrowser.git", + "clone_url": "https://github.com/mralexgray/AHContentBrowser.git", + "svn_url": "https://github.com/mralexgray/AHContentBrowser", + "homepage": "", + "size": 223, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Objective-C", + "has_issues": false, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 9167473, + "name": "AHLayout", + "full_name": "mralexgray/AHLayout", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/AHLayout", + "description": "AHLayout", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/AHLayout", + "forks_url": "https://api.github.com/repos/mralexgray/AHLayout/forks", + "keys_url": "https://api.github.com/repos/mralexgray/AHLayout/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/AHLayout/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/AHLayout/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/AHLayout/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/AHLayout/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/AHLayout/events", + "assignees_url": "https://api.github.com/repos/mralexgray/AHLayout/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/AHLayout/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/AHLayout/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/AHLayout/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/AHLayout/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/AHLayout/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/AHLayout/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/AHLayout/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/AHLayout/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/AHLayout/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/AHLayout/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/AHLayout/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/AHLayout/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/AHLayout/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/AHLayout/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/AHLayout/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/AHLayout/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/AHLayout/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/AHLayout/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/AHLayout/merges", + "archive_url": "https://api.github.com/repos/mralexgray/AHLayout/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/AHLayout/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/AHLayout/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/AHLayout/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/AHLayout/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/AHLayout/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/AHLayout/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/AHLayout/releases{/id}", + "created_at": "2013-04-02T10:10:30Z", + "updated_at": "2013-07-08T02:31:17Z", + "pushed_at": "2013-07-08T02:31:14Z", + "git_url": "git://github.com/mralexgray/AHLayout.git", + "ssh_url": "git@github.com:mralexgray/AHLayout.git", + "clone_url": "https://github.com/mralexgray/AHLayout.git", + "svn_url": "https://github.com/mralexgray/AHLayout", + "homepage": null, + "size": 359, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Objective-C", + "has_issues": false, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 18450201, + "name": "Airmail-Plug-In-Framework", + "full_name": "mralexgray/Airmail-Plug-In-Framework", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/Airmail-Plug-In-Framework", + "description": "", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework", + "forks_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/forks", + "keys_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/events", + "assignees_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/merges", + "archive_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/Airmail-Plug-In-Framework/releases{/id}", + "created_at": "2014-04-04T19:33:54Z", + "updated_at": "2014-04-04T19:33:54Z", + "pushed_at": "2014-03-27T15:42:19Z", + "git_url": "git://github.com/mralexgray/Airmail-Plug-In-Framework.git", + "ssh_url": "git@github.com:mralexgray/Airmail-Plug-In-Framework.git", + "clone_url": "https://github.com/mralexgray/Airmail-Plug-In-Framework.git", + "svn_url": "https://github.com/mralexgray/Airmail-Plug-In-Framework", + "homepage": null, + "size": 888, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": false, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 5203219, + "name": "AJS-iTunes-API", + "full_name": "mralexgray/AJS-iTunes-API", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/AJS-iTunes-API", + "description": "Cocoa wrapper for the iTunes search API - for iOS and Mac OSX projects", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API", + "forks_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/forks", + "keys_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/events", + "assignees_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/merges", + "archive_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/AJS-iTunes-API/releases{/id}", + "created_at": "2012-07-27T10:20:58Z", + "updated_at": "2013-01-11T11:00:05Z", + "pushed_at": "2011-10-30T22:26:48Z", + "git_url": "git://github.com/mralexgray/AJS-iTunes-API.git", + "ssh_url": "git@github.com:mralexgray/AJS-iTunes-API.git", + "clone_url": "https://github.com/mralexgray/AJS-iTunes-API.git", + "svn_url": "https://github.com/mralexgray/AJS-iTunes-API", + "homepage": "", + "size": 103, + "stargazers_count": 1, + "watchers_count": 1, + "language": "Objective-C", + "has_issues": false, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 1, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 10093801, + "name": "Alcatraz", + "full_name": "mralexgray/Alcatraz", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/Alcatraz", + "description": "The most awesome (and only) Xcode package manager!", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/Alcatraz", + "forks_url": "https://api.github.com/repos/mralexgray/Alcatraz/forks", + "keys_url": "https://api.github.com/repos/mralexgray/Alcatraz/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/Alcatraz/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/Alcatraz/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/Alcatraz/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/Alcatraz/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/Alcatraz/events", + "assignees_url": "https://api.github.com/repos/mralexgray/Alcatraz/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/Alcatraz/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/Alcatraz/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/Alcatraz/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/Alcatraz/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/Alcatraz/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/Alcatraz/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/Alcatraz/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/Alcatraz/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/Alcatraz/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/Alcatraz/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/Alcatraz/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/Alcatraz/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/Alcatraz/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/Alcatraz/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/Alcatraz/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/Alcatraz/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/Alcatraz/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/Alcatraz/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/Alcatraz/merges", + "archive_url": "https://api.github.com/repos/mralexgray/Alcatraz/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/Alcatraz/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/Alcatraz/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/Alcatraz/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/Alcatraz/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/Alcatraz/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/Alcatraz/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/Alcatraz/releases{/id}", + "created_at": "2013-05-16T04:41:13Z", + "updated_at": "2014-03-19T20:38:35Z", + "pushed_at": "2014-03-19T12:50:37Z", + "git_url": "git://github.com/mralexgray/Alcatraz.git", + "ssh_url": "git@github.com:mralexgray/Alcatraz.git", + "clone_url": "https://github.com/mralexgray/Alcatraz.git", + "svn_url": "https://github.com/mralexgray/Alcatraz", + "homepage": "mneorr.github.com/Alcatraz", + "size": 3668, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Objective-C", + "has_issues": false, + "has_downloads": true, + "has_wiki": false, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 12916552, + "name": "alcatraz-packages", + "full_name": "mralexgray/alcatraz-packages", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/alcatraz-packages", + "description": "Package list repository for Alcatraz", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/alcatraz-packages", + "forks_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/forks", + "keys_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/events", + "assignees_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/merges", + "archive_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/alcatraz-packages/releases{/id}", + "created_at": "2013-09-18T07:15:24Z", + "updated_at": "2013-09-18T07:15:25Z", + "pushed_at": "2013-09-09T07:51:48Z", + "git_url": "git://github.com/mralexgray/alcatraz-packages.git", + "ssh_url": "git@github.com:mralexgray/alcatraz-packages.git", + "clone_url": "https://github.com/mralexgray/alcatraz-packages.git", + "svn_url": "https://github.com/mralexgray/alcatraz-packages", + "homepage": "mneorr.github.com/Alcatraz", + "size": 482, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Ruby", + "has_issues": false, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 10476467, + "name": "Alfred-Google-Translate", + "full_name": "mralexgray/Alfred-Google-Translate", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/Alfred-Google-Translate", + "description": "Extension for Alfred that will do a Google translate for you", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate", + "forks_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/forks", + "keys_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/events", + "assignees_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/merges", + "archive_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/Alfred-Google-Translate/releases{/id}", + "created_at": "2013-06-04T10:45:10Z", + "updated_at": "2013-06-04T10:45:10Z", + "pushed_at": "2013-01-12T19:39:03Z", + "git_url": "git://github.com/mralexgray/Alfred-Google-Translate.git", + "ssh_url": "git@github.com:mralexgray/Alfred-Google-Translate.git", + "clone_url": "https://github.com/mralexgray/Alfred-Google-Translate.git", + "svn_url": "https://github.com/mralexgray/Alfred-Google-Translate", + "homepage": null, + "size": 103, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Shell", + "has_issues": false, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 5524019, + "name": "Amber", + "full_name": "mralexgray/Amber", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/Amber", + "description": "Fork of the difficult-to-deal-with Amber.framework", + "fork": false, + "url": "https://api.github.com/repos/mralexgray/Amber", + "forks_url": "https://api.github.com/repos/mralexgray/Amber/forks", + "keys_url": "https://api.github.com/repos/mralexgray/Amber/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/Amber/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/Amber/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/Amber/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/Amber/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/Amber/events", + "assignees_url": "https://api.github.com/repos/mralexgray/Amber/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/Amber/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/Amber/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/Amber/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/Amber/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/Amber/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/Amber/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/Amber/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/Amber/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/Amber/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/Amber/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/Amber/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/Amber/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/Amber/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/Amber/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/Amber/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/Amber/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/Amber/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/Amber/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/Amber/merges", + "archive_url": "https://api.github.com/repos/mralexgray/Amber/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/Amber/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/Amber/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/Amber/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/Amber/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/Amber/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/Amber/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/Amber/releases{/id}", + "created_at": "2012-08-23T10:38:24Z", + "updated_at": "2013-01-11T22:25:35Z", + "pushed_at": "2012-08-23T10:38:25Z", + "git_url": "git://github.com/mralexgray/Amber.git", + "ssh_url": "git@github.com:mralexgray/Amber.git", + "clone_url": "https://github.com/mralexgray/Amber.git", + "svn_url": "https://github.com/mralexgray/Amber", + "homepage": null, + "size": 48, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 10809060, + "name": "Amethyst", + "full_name": "mralexgray/Amethyst", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/Amethyst", + "description": "Tiling window manager for OS X.", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/Amethyst", + "forks_url": "https://api.github.com/repos/mralexgray/Amethyst/forks", + "keys_url": "https://api.github.com/repos/mralexgray/Amethyst/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/Amethyst/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/Amethyst/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/Amethyst/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/Amethyst/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/Amethyst/events", + "assignees_url": "https://api.github.com/repos/mralexgray/Amethyst/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/Amethyst/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/Amethyst/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/Amethyst/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/Amethyst/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/Amethyst/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/Amethyst/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/Amethyst/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/Amethyst/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/Amethyst/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/Amethyst/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/Amethyst/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/Amethyst/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/Amethyst/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/Amethyst/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/Amethyst/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/Amethyst/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/Amethyst/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/Amethyst/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/Amethyst/merges", + "archive_url": "https://api.github.com/repos/mralexgray/Amethyst/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/Amethyst/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/Amethyst/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/Amethyst/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/Amethyst/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/Amethyst/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/Amethyst/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/Amethyst/releases{/id}", + "created_at": "2013-06-20T00:34:22Z", + "updated_at": "2013-06-20T00:34:22Z", + "pushed_at": "2013-06-18T02:54:11Z", + "git_url": "git://github.com/mralexgray/Amethyst.git", + "ssh_url": "git@github.com:mralexgray/Amethyst.git", + "clone_url": "https://github.com/mralexgray/Amethyst.git", + "svn_url": "https://github.com/mralexgray/Amethyst", + "homepage": "http://ianyh.github.io/Amethyst/", + "size": 12623, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Objective-C", + "has_issues": false, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 3684286, + "name": "Animated-Paths", + "full_name": "mralexgray/Animated-Paths", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/Animated-Paths", + "description": "Demo project: Animating the drawing of a CGPath with CAShapeLayer.strokeEnd", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/Animated-Paths", + "forks_url": "https://api.github.com/repos/mralexgray/Animated-Paths/forks", + "keys_url": "https://api.github.com/repos/mralexgray/Animated-Paths/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/Animated-Paths/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/Animated-Paths/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/Animated-Paths/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/Animated-Paths/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/Animated-Paths/events", + "assignees_url": "https://api.github.com/repos/mralexgray/Animated-Paths/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/Animated-Paths/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/Animated-Paths/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/Animated-Paths/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/Animated-Paths/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/Animated-Paths/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/Animated-Paths/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/Animated-Paths/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/Animated-Paths/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/Animated-Paths/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/Animated-Paths/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/Animated-Paths/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/Animated-Paths/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/Animated-Paths/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/Animated-Paths/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/Animated-Paths/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/Animated-Paths/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/Animated-Paths/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/Animated-Paths/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/Animated-Paths/merges", + "archive_url": "https://api.github.com/repos/mralexgray/Animated-Paths/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/Animated-Paths/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/Animated-Paths/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/Animated-Paths/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/Animated-Paths/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/Animated-Paths/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/Animated-Paths/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/Animated-Paths/releases{/id}", + "created_at": "2012-03-11T02:56:38Z", + "updated_at": "2013-01-08T04:12:21Z", + "pushed_at": "2010-12-30T20:56:51Z", + "git_url": "git://github.com/mralexgray/Animated-Paths.git", + "ssh_url": "git@github.com:mralexgray/Animated-Paths.git", + "clone_url": "https://github.com/mralexgray/Animated-Paths.git", + "svn_url": "https://github.com/mralexgray/Animated-Paths", + "homepage": "http://oleb.net/blog/2010/12/animating-drawing-of-cgpath-with-cashapelayer/", + "size": 411, + "stargazers_count": 1, + "watchers_count": 1, + "language": "Objective-C", + "has_issues": false, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 1, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 16662874, + "name": "AnsiLove.framework", + "full_name": "mralexgray/AnsiLove.framework", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/AnsiLove.framework", + "description": "Cocoa Framework for rendering ANSi / ASCII art", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/AnsiLove.framework", + "forks_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/forks", + "keys_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/events", + "assignees_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/merges", + "archive_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/AnsiLove.framework/releases{/id}", + "created_at": "2014-02-09T08:30:27Z", + "updated_at": "2014-02-09T08:30:32Z", + "pushed_at": "2013-10-04T14:08:38Z", + "git_url": "git://github.com/mralexgray/AnsiLove.framework.git", + "ssh_url": "git@github.com:mralexgray/AnsiLove.framework.git", + "clone_url": "https://github.com/mralexgray/AnsiLove.framework.git", + "svn_url": "https://github.com/mralexgray/AnsiLove.framework", + "homepage": "http://byteproject.net", + "size": 3780, + "stargazers_count": 0, + "watchers_count": 0, + "language": "M", + "has_issues": false, + "has_downloads": true, + "has_wiki": false, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 5189563, + "name": "ANTrackBar", + "full_name": "mralexgray/ANTrackBar", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/ANTrackBar", + "description": "An easy-to-use Cocoa seek bar with a pleasing appearance", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/ANTrackBar", + "forks_url": "https://api.github.com/repos/mralexgray/ANTrackBar/forks", + "keys_url": "https://api.github.com/repos/mralexgray/ANTrackBar/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/ANTrackBar/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/ANTrackBar/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/ANTrackBar/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/ANTrackBar/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/ANTrackBar/events", + "assignees_url": "https://api.github.com/repos/mralexgray/ANTrackBar/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/ANTrackBar/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/ANTrackBar/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/ANTrackBar/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/ANTrackBar/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/ANTrackBar/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/ANTrackBar/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/ANTrackBar/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/ANTrackBar/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/ANTrackBar/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/ANTrackBar/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/ANTrackBar/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/ANTrackBar/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/ANTrackBar/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/ANTrackBar/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/ANTrackBar/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/ANTrackBar/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/ANTrackBar/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/ANTrackBar/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/ANTrackBar/merges", + "archive_url": "https://api.github.com/repos/mralexgray/ANTrackBar/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/ANTrackBar/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/ANTrackBar/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/ANTrackBar/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/ANTrackBar/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/ANTrackBar/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/ANTrackBar/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/ANTrackBar/releases{/id}", + "created_at": "2012-07-26T08:17:22Z", + "updated_at": "2013-01-11T10:29:56Z", + "pushed_at": "2012-03-09T01:40:02Z", + "git_url": "git://github.com/mralexgray/ANTrackBar.git", + "ssh_url": "git@github.com:mralexgray/ANTrackBar.git", + "clone_url": "https://github.com/mralexgray/ANTrackBar.git", + "svn_url": "https://github.com/mralexgray/ANTrackBar", + "homepage": "", + "size": 94, + "stargazers_count": 1, + "watchers_count": 1, + "language": "Objective-C", + "has_issues": false, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 1, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 16240152, + "name": "AOP-in-Objective-C", + "full_name": "mralexgray/AOP-in-Objective-C", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/AOP-in-Objective-C", + "description": "An NSProxy based library for easily enabling AOP like functionality in Objective-C.", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C", + "forks_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/forks", + "keys_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/events", + "assignees_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/merges", + "archive_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/AOP-in-Objective-C/releases{/id}", + "created_at": "2014-01-25T21:18:04Z", + "updated_at": "2014-02-12T16:23:21Z", + "pushed_at": "2014-02-12T16:23:20Z", + "git_url": "git://github.com/mralexgray/AOP-in-Objective-C.git", + "ssh_url": "git@github.com:mralexgray/AOP-in-Objective-C.git", + "clone_url": "https://github.com/mralexgray/AOP-in-Objective-C.git", + "svn_url": "https://github.com/mralexgray/AOP-in-Objective-C", + "homepage": "http://innoli.hu/en/opensource/", + "size": 340, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Objective-C", + "has_issues": false, + "has_downloads": true, + "has_wiki": true, + "forks_count": 1, + "mirror_url": null, + "open_issues_count": 0, + "forks": 1, + "open_issues": 0, + "watchers": 0, + "default_branch": "travis-coveralls", + "master_branch": "travis-coveralls" + }, + { + "id": 13141936, + "name": "Apaxy", + "full_name": "mralexgray/Apaxy", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/Apaxy", + "description": "A simple, customisable theme for your Apache directory listing.", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/Apaxy", + "forks_url": "https://api.github.com/repos/mralexgray/Apaxy/forks", + "keys_url": "https://api.github.com/repos/mralexgray/Apaxy/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/Apaxy/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/Apaxy/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/Apaxy/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/Apaxy/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/Apaxy/events", + "assignees_url": "https://api.github.com/repos/mralexgray/Apaxy/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/Apaxy/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/Apaxy/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/Apaxy/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/Apaxy/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/Apaxy/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/Apaxy/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/Apaxy/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/Apaxy/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/Apaxy/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/Apaxy/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/Apaxy/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/Apaxy/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/Apaxy/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/Apaxy/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/Apaxy/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/Apaxy/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/Apaxy/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/Apaxy/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/Apaxy/merges", + "archive_url": "https://api.github.com/repos/mralexgray/Apaxy/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/Apaxy/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/Apaxy/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/Apaxy/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/Apaxy/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/Apaxy/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/Apaxy/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/Apaxy/releases{/id}", + "created_at": "2013-09-27T05:05:35Z", + "updated_at": "2013-09-27T05:05:36Z", + "pushed_at": "2013-08-02T16:01:32Z", + "git_url": "git://github.com/mralexgray/Apaxy.git", + "ssh_url": "git@github.com:mralexgray/Apaxy.git", + "clone_url": "https://github.com/mralexgray/Apaxy.git", + "svn_url": "https://github.com/mralexgray/Apaxy", + "homepage": null, + "size": 113, + "stargazers_count": 0, + "watchers_count": 0, + "language": "CSS", + "has_issues": false, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 10048098, + "name": "appledoc", + "full_name": "mralexgray/appledoc", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/appledoc", + "description": "Objective-c code Apple style documentation set generator.", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/appledoc", + "forks_url": "https://api.github.com/repos/mralexgray/appledoc/forks", + "keys_url": "https://api.github.com/repos/mralexgray/appledoc/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/appledoc/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/appledoc/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/appledoc/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/appledoc/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/appledoc/events", + "assignees_url": "https://api.github.com/repos/mralexgray/appledoc/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/appledoc/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/appledoc/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/appledoc/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/appledoc/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/appledoc/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/appledoc/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/appledoc/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/appledoc/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/appledoc/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/appledoc/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/appledoc/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/appledoc/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/appledoc/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/appledoc/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/appledoc/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/appledoc/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/appledoc/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/appledoc/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/appledoc/merges", + "archive_url": "https://api.github.com/repos/mralexgray/appledoc/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/appledoc/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/appledoc/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/appledoc/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/appledoc/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/appledoc/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/appledoc/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/appledoc/releases{/id}", + "created_at": "2013-05-14T05:45:44Z", + "updated_at": "2014-02-09T08:14:42Z", + "pushed_at": "2014-02-09T08:14:42Z", + "git_url": "git://github.com/mralexgray/appledoc.git", + "ssh_url": "git@github.com:mralexgray/appledoc.git", + "clone_url": "https://github.com/mralexgray/appledoc.git", + "svn_url": "https://github.com/mralexgray/appledoc", + "homepage": "http://gentlebytes.com", + "size": 10336, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Objective-C", + "has_issues": false, + "has_downloads": false, + "has_wiki": false, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 16160992, + "name": "Appstore-Through-Terminal", + "full_name": "mralexgray/Appstore-Through-Terminal", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/Appstore-Through-Terminal", + "description": "A simple debian package, made for iPhone, to open the iOS AppStore through terminal. Simple. Slightly usless. My work as a beginner.", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal", + "forks_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/forks", + "keys_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/events", + "assignees_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/merges", + "archive_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/Appstore-Through-Terminal/releases{/id}", + "created_at": "2014-01-23T03:21:34Z", + "updated_at": "2014-01-23T03:21:34Z", + "pushed_at": "2011-12-21T06:40:25Z", + "git_url": "git://github.com/mralexgray/Appstore-Through-Terminal.git", + "ssh_url": "git@github.com:mralexgray/Appstore-Through-Terminal.git", + "clone_url": "https://github.com/mralexgray/Appstore-Through-Terminal.git", + "svn_url": "https://github.com/mralexgray/Appstore-Through-Terminal", + "homepage": "http://getagripon.com/tillie/projects.html", + "size": 104, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Shell", + "has_issues": false, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 13709216, + "name": "appweb-4", + "full_name": "mralexgray/appweb-4", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/appweb-4", + "description": "Appweb Embeddable Web Server 4", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/appweb-4", + "forks_url": "https://api.github.com/repos/mralexgray/appweb-4/forks", + "keys_url": "https://api.github.com/repos/mralexgray/appweb-4/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/appweb-4/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/appweb-4/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/appweb-4/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/appweb-4/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/appweb-4/events", + "assignees_url": "https://api.github.com/repos/mralexgray/appweb-4/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/appweb-4/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/appweb-4/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/appweb-4/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/appweb-4/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/appweb-4/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/appweb-4/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/appweb-4/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/appweb-4/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/appweb-4/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/appweb-4/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/appweb-4/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/appweb-4/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/appweb-4/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/appweb-4/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/appweb-4/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/appweb-4/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/appweb-4/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/appweb-4/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/appweb-4/merges", + "archive_url": "https://api.github.com/repos/mralexgray/appweb-4/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/appweb-4/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/appweb-4/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/appweb-4/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/appweb-4/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/appweb-4/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/appweb-4/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/appweb-4/releases{/id}", + "created_at": "2013-10-19T21:36:10Z", + "updated_at": "2013-10-19T21:36:11Z", + "pushed_at": "2013-10-19T00:35:06Z", + "git_url": "git://github.com/mralexgray/appweb-4.git", + "ssh_url": "git@github.com:mralexgray/appweb-4.git", + "clone_url": "https://github.com/mralexgray/appweb-4.git", + "svn_url": "https://github.com/mralexgray/appweb-4", + "homepage": "http://appwebserver.org", + "size": 58244, + "stargazers_count": 0, + "watchers_count": 0, + "language": "C", + "has_issues": false, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 12501983, + "name": "arbor", + "full_name": "mralexgray/arbor", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/arbor", + "description": "a graph visualization library using web workers and jQuery", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/arbor", + "forks_url": "https://api.github.com/repos/mralexgray/arbor/forks", + "keys_url": "https://api.github.com/repos/mralexgray/arbor/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/arbor/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/arbor/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/arbor/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/arbor/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/arbor/events", + "assignees_url": "https://api.github.com/repos/mralexgray/arbor/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/arbor/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/arbor/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/arbor/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/arbor/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/arbor/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/arbor/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/arbor/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/arbor/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/arbor/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/arbor/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/arbor/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/arbor/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/arbor/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/arbor/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/arbor/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/arbor/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/arbor/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/arbor/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/arbor/merges", + "archive_url": "https://api.github.com/repos/mralexgray/arbor/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/arbor/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/arbor/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/arbor/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/arbor/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/arbor/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/arbor/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/arbor/releases{/id}", + "created_at": "2013-08-31T07:07:05Z", + "updated_at": "2013-08-31T07:07:06Z", + "pushed_at": "2012-05-28T00:47:58Z", + "git_url": "git://github.com/mralexgray/arbor.git", + "ssh_url": "git@github.com:mralexgray/arbor.git", + "clone_url": "https://github.com/mralexgray/arbor.git", + "svn_url": "https://github.com/mralexgray/arbor", + "homepage": "http://arborjs.org", + "size": 237, + "stargazers_count": 0, + "watchers_count": 0, + "language": "JavaScript", + "has_issues": false, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 13537888, + "name": "Archimedes", + "full_name": "mralexgray/Archimedes", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/Archimedes", + "description": "Geometry functions for Cocoa and Cocoa Touch", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/Archimedes", + "forks_url": "https://api.github.com/repos/mralexgray/Archimedes/forks", + "keys_url": "https://api.github.com/repos/mralexgray/Archimedes/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/Archimedes/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/Archimedes/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/Archimedes/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/Archimedes/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/Archimedes/events", + "assignees_url": "https://api.github.com/repos/mralexgray/Archimedes/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/Archimedes/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/Archimedes/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/Archimedes/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/Archimedes/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/Archimedes/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/Archimedes/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/Archimedes/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/Archimedes/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/Archimedes/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/Archimedes/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/Archimedes/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/Archimedes/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/Archimedes/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/Archimedes/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/Archimedes/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/Archimedes/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/Archimedes/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/Archimedes/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/Archimedes/merges", + "archive_url": "https://api.github.com/repos/mralexgray/Archimedes/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/Archimedes/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/Archimedes/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/Archimedes/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/Archimedes/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/Archimedes/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/Archimedes/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/Archimedes/releases{/id}", + "created_at": "2013-10-13T11:08:19Z", + "updated_at": "2014-04-06T00:41:21Z", + "pushed_at": "2014-04-06T00:41:20Z", + "git_url": "git://github.com/mralexgray/Archimedes.git", + "ssh_url": "git@github.com:mralexgray/Archimedes.git", + "clone_url": "https://github.com/mralexgray/Archimedes.git", + "svn_url": "https://github.com/mralexgray/Archimedes", + "homepage": null, + "size": 217, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Objective-C", + "has_issues": false, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "master_branch": "master" + }, + { + "id": 5260205, + "name": "arrsync", + "full_name": "mralexgray/arrsync", + "owner": { + "login": "mralexgray", + "id": 262517, + "avatar_url": "https://avatars.githubusercontent.com/u/262517?", + "gravatar_id": "50e7ed4eb2e7af000ea7d161748958f1", + "url": "https://api.github.com/users/mralexgray", + "html_url": "https://github.com/mralexgray", + "followers_url": "https://api.github.com/users/mralexgray/followers", + "following_url": "https://api.github.com/users/mralexgray/following{/other_user}", + "gists_url": "https://api.github.com/users/mralexgray/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mralexgray/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mralexgray/subscriptions", + "organizations_url": "https://api.github.com/users/mralexgray/orgs", + "repos_url": "https://api.github.com/users/mralexgray/repos", + "events_url": "https://api.github.com/users/mralexgray/events{/privacy}", + "received_events_url": "https://api.github.com/users/mralexgray/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/mralexgray/arrsync", + "description": "", + "fork": true, + "url": "https://api.github.com/repos/mralexgray/arrsync", + "forks_url": "https://api.github.com/repos/mralexgray/arrsync/forks", + "keys_url": "https://api.github.com/repos/mralexgray/arrsync/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/mralexgray/arrsync/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/mralexgray/arrsync/teams", + "hooks_url": "https://api.github.com/repos/mralexgray/arrsync/hooks", + "issue_events_url": "https://api.github.com/repos/mralexgray/arrsync/issues/events{/number}", + "events_url": "https://api.github.com/repos/mralexgray/arrsync/events", + "assignees_url": "https://api.github.com/repos/mralexgray/arrsync/assignees{/user}", + "branches_url": "https://api.github.com/repos/mralexgray/arrsync/branches{/branch}", + "tags_url": "https://api.github.com/repos/mralexgray/arrsync/tags", + "blobs_url": "https://api.github.com/repos/mralexgray/arrsync/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/mralexgray/arrsync/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/mralexgray/arrsync/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/mralexgray/arrsync/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/mralexgray/arrsync/statuses/{sha}", + "languages_url": "https://api.github.com/repos/mralexgray/arrsync/languages", + "stargazers_url": "https://api.github.com/repos/mralexgray/arrsync/stargazers", + "contributors_url": "https://api.github.com/repos/mralexgray/arrsync/contributors", + "subscribers_url": "https://api.github.com/repos/mralexgray/arrsync/subscribers", + "subscription_url": "https://api.github.com/repos/mralexgray/arrsync/subscription", + "commits_url": "https://api.github.com/repos/mralexgray/arrsync/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/mralexgray/arrsync/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/mralexgray/arrsync/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/mralexgray/arrsync/issues/comments/{number}", + "contents_url": "https://api.github.com/repos/mralexgray/arrsync/contents/{+path}", + "compare_url": "https://api.github.com/repos/mralexgray/arrsync/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/mralexgray/arrsync/merges", + "archive_url": "https://api.github.com/repos/mralexgray/arrsync/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/mralexgray/arrsync/downloads", + "issues_url": "https://api.github.com/repos/mralexgray/arrsync/issues{/number}", + "pulls_url": "https://api.github.com/repos/mralexgray/arrsync/pulls{/number}", + "milestones_url": "https://api.github.com/repos/mralexgray/arrsync/milestones{/number}", + "notifications_url": "https://api.github.com/repos/mralexgray/arrsync/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/mralexgray/arrsync/labels{/name}", + "releases_url": "https://api.github.com/repos/mralexgray/arrsync/releases{/id}", + "created_at": "2012-08-01T14:21:49Z", + "updated_at": "2013-01-11T13:12:21Z", + "pushed_at": "2011-05-09T18:56:56Z", + "git_url": "git://github.com/mralexgray/arrsync.git", + "ssh_url": "git@github.com:mralexgray/arrsync.git", + "clone_url": "https://github.com/mralexgray/arrsync.git", + "svn_url": "https://github.com/mralexgray/arrsync", + "homepage": "", + "size": 194, + "stargazers_count": 2, + "watchers_count": 2, + "language": "Objective-C", + "has_issues": false, + "has_downloads": true, + "has_wiki": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 0, + "forks": 0, + "open_issues": 0, + "watchers": 2, + "default_branch": "master", + "master_branch": "master" + } +] +}
\ No newline at end of file diff --git a/libccnx-common/ccnx/common/test/test_ccnx_ContentObject.c b/libccnx-common/ccnx/common/test/test_ccnx_ContentObject.c new file mode 100755 index 00000000..20ed8c13 --- /dev/null +++ b/libccnx-common/ccnx/common/test/test_ccnx_ContentObject.c @@ -0,0 +1,634 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnx_ContentObject.c" + +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +#include <inttypes.h> +#include <stdio.h> + +typedef struct test_data { + CCNxContentObjectInterface impl; + CCNxName *name; + CCNxContentObject *contentObject; + CCNxContentObject *namelessContentObject; +} TestData; + +LONGBOW_TEST_RUNNER(ccnx_ContentObject) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(EmptyImpl); +} + +static TestData * +_commonSetup(void) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + + CCNxName *name = ccnxName_CreateFromCString("ccnx:/default/testData/content"); + PARCBuffer *payload = parcBuffer_WrapCString("hello"); + + data->impl = CCNxContentObjectFacadeV1_Implementation; + data->name = name; + data->contentObject = ccnxContentObject_CreateWithImplAndPayload(&data->impl, name, CCNxPayloadType_DATA, payload); + data->namelessContentObject = ccnxContentObject_CreateWithImplAndPayload(&data->impl, NULL, CCNxPayloadType_DATA, payload); + + parcBuffer_Release(&payload); + return data; +} + +static void +_commonTeardown(TestData *data) +{ + if (data->contentObject) { + ccnxContentObject_Release(&data->contentObject); + } + if (data->namelessContentObject) { + ccnxContentObject_Release(&data->namelessContentObject); + } + if (data->name) { + ccnxName_Release(&data->name); + } + + parcMemory_Deallocate((void **) &data); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnx_ContentObject) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_ContentObject) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_Equals); + LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_SetSignature); + LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_GetKeyId); + LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_CreateWithNameAndPayload); + LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_CreateWithPayload); + + LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_HasFinalChunkNumber); + LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_GetSetFinalChunkNumber); + + LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_GetName); + LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_GetNameWithNameless); + LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_GetPayload); + LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_GetPayloadType); + LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_AcquireRelease); + + LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_HasExpiryTime); + LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_SetGetExpiryTime); + + LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_Equals); + LONGBOW_RUN_TEST_CASE(Global, ccnxContentObject_Display); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + longBowTestCase_SetClipBoardData(testCase, _commonSetup()); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + _commonTeardown(longBowTestCase_GetClipBoardData(testCase)); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + + +LONGBOW_TEST_CASE(Global, ccnxContentObject_CreateWithNameAndPayload) +{ + CCNxName *name = ccnxName_CreateFromCString("ccnx:/foo/bar"); + PARCBuffer *payload = parcBuffer_Allocate(100); + + CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload); + ccnxContentObject_AssertValid(contentObject); + + ccnxName_Release(&name); + parcBuffer_Release(&payload); + ccnxContentObject_Release(&contentObject); +} + +LONGBOW_TEST_CASE(Global, ccnxContentObject_CreateWithPayload) +{ + PARCBuffer *payload = parcBuffer_Allocate(100); + + CCNxContentObject *contentObject = ccnxContentObject_CreateWithPayload(payload); + ccnxContentObject_AssertValid(contentObject); + + parcBuffer_Release(&payload); + ccnxContentObject_Release(&contentObject); +} + + +LONGBOW_TEST_CASE(Global, ccnxContentObject_Equals) +{ + CCNxName *nameA = ccnxName_CreateFromCString("ccnx:/foo/bar/A"); + PARCBuffer *payloadA = parcBuffer_Allocate(100); + + CCNxContentObject *objectA = ccnxContentObject_CreateWithNameAndPayload(nameA, payloadA); + ccnxContentObject_AssertValid(objectA); + + assertTrue(ccnxContentObject_Equals(objectA, objectA), "Expected same instance to be equal"); + + CCNxContentObject *objectA2 = ccnxContentObject_CreateWithNameAndPayload(nameA, payloadA); + ccnxContentObject_AssertValid(objectA2); + + assertTrue(ccnxContentObject_Equals(objectA, objectA2), "Expected ContentObject with same payload and name to be equal"); + + CCNxName *nameB = ccnxName_CreateFromCString("ccnx:/foo/bar/B"); + CCNxContentObject *objectB = ccnxContentObject_CreateWithNameAndPayload(nameB, payloadA); + ccnxContentObject_AssertValid(objectB); + + assertFalse(ccnxContentObject_Equals(objectA, objectB), "Expected ContentObject with same payload and different name"); + + ccnxName_Release(&nameA); + ccnxName_Release(&nameB); + parcBuffer_Release(&payloadA); + + ccnxContentObject_Release(&objectA); + ccnxContentObject_Release(&objectA2); + ccnxContentObject_Release(&objectB); +} + +LONGBOW_TEST_CASE(Global, ccnxContentObject_AcquireRelease) +{ + CCNxName *name = ccnxName_CreateFromCString("ccnx:/foo/bar"); + PARCBuffer *payload = parcBuffer_Allocate(100); + + CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload); + ccnxContentObject_AssertValid(contentObject); + + CCNxContentObject *reference = ccnxContentObject_Acquire(contentObject); + assertTrue(reference == contentObject, "Expected acquired reference to be equal to original"); + + ccnxName_Release(&name); + parcBuffer_Release(&payload); + + ccnxContentObject_AssertValid(contentObject); + ccnxContentObject_AssertValid(reference); + + ccnxContentObject_Release(&contentObject); + + assertTrue(contentObject == NULL, "Expected contentObject pointer to be null"); + ccnxContentObject_AssertValid(reference); + + ccnxContentObject_Release(&reference); + + assertTrue(reference == NULL, "Expected contentObject pointer to be null"); +} + +LONGBOW_TEST_CASE(Global, ccnxContentObject_HasFinalChunkNumber) +{ + CCNxName *name = ccnxName_CreateFromCString("ccnx:/foo/bar"); + PARCBuffer *payload = parcBuffer_Allocate(100); + + CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload); + assertFalse(ccnxContentObject_HasFinalChunkNumber(contentObject), "Expected no final chunk number"); + + ccnxContentObject_SetFinalChunkNumber(contentObject, 100); + ccnxContentObject_AssertValid(contentObject); + assertTrue(ccnxContentObject_HasFinalChunkNumber(contentObject), "Expected HasFinalChunkNumber to return true"); + assertTrue(ccnxContentObject_GetFinalChunkNumber(contentObject) == 100, "Expected final chunk number to be 100"); + + ccnxName_Release(&name); + parcBuffer_Release(&payload); + ccnxContentObject_Release(&contentObject); +} + +LONGBOW_TEST_CASE(Global, ccnxContentObject_GetSetFinalChunkNumber) +{ + CCNxName *name = ccnxName_CreateFromCString("ccnx:/foo/bar"); + PARCBuffer *payload = parcBuffer_Allocate(100); + + CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload); + + ccnxContentObject_SetFinalChunkNumber(contentObject, 100); + ccnxContentObject_AssertValid(contentObject); + assertTrue(ccnxContentObject_GetFinalChunkNumber(contentObject) == 100, "Expected final chunk number to be 100"); + + ccnxContentObject_SetFinalChunkNumber(contentObject, 20010); + ccnxContentObject_AssertValid(contentObject); + assertTrue(ccnxContentObject_GetFinalChunkNumber(contentObject) == 20010, "Expected final chunk number to be 20010"); + + ccnxName_Release(&name); + parcBuffer_Release(&payload); + ccnxContentObject_Release(&contentObject); +} + +LONGBOW_TEST_CASE(Global, ccnxContentObject_GetName) +{ + CCNxName *name = ccnxName_CreateFromCString("ccnx:/foo/bar/baz"); + PARCBuffer *payload = parcBuffer_Allocate(100); + + CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload); + ccnxContentObject_AssertValid(contentObject); + + CCNxName *actual = ccnxContentObject_GetName(contentObject); + + assertTrue(actual == name, "Expected GetName() to return the original CCNxName"); + + ccnxName_Release(&name); + parcBuffer_Release(&payload); + ccnxContentObject_Release(&contentObject); +} + +LONGBOW_TEST_CASE(Global, ccnxContentObject_GetNameWithNameless) +{ + PARCBuffer *payload = parcBuffer_Allocate(100); + + CCNxContentObject *contentObject = ccnxContentObject_CreateWithPayload(payload); + ccnxContentObject_AssertValid(contentObject); + + CCNxName *actual = ccnxContentObject_GetName(contentObject); + + assertNull(actual, "Nameless CCNxContentObjects have no name and must therefore be null."); + + parcBuffer_Release(&payload); + ccnxContentObject_Release(&contentObject); +} + +LONGBOW_TEST_CASE(Global, ccnxContentObject_GetPayload) +{ + CCNxName *name = ccnxName_CreateFromCString("ccnx:/foo/bar"); + PARCBuffer *payload = parcBuffer_Allocate(100); + + CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload); + ccnxContentObject_AssertValid(contentObject); + + PARCBuffer *actual = ccnxContentObject_GetPayload(contentObject); + + assertTrue(actual == payload, "Expected GetPayload() to return the original PARCBuffer"); + + ccnxName_Release(&name); + parcBuffer_Release(&payload); + ccnxContentObject_Release(&contentObject); +} + +LONGBOW_TEST_CASE(Global, ccnxContentObject_GetPayloadType) +{ + CCNxName *name = ccnxName_CreateFromCString("ccnx:/name"); + PARCBuffer *payload = parcBuffer_Allocate(100); + + CCNxPayloadType types[] = { + CCNxPayloadType_DATA, + CCNxPayloadType_KEY, + CCNxPayloadType_LINK, + CCNxPayloadType_MANIFEST, + }; + + + for (int i = 0; i < sizeof(types) / sizeof(CCNxPayloadType); i++) { + CCNxPayloadType type = types[i]; + CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, NULL); + ccnxContentObject_SetPayload(contentObject, type, payload); + + assertTrue(ccnxContentObject_GetPayloadType(contentObject) == type, "Unexpected PayloadType"); + ccnxContentObject_Release(&contentObject); + } + + parcBuffer_Release(&payload); + ccnxName_Release(&name); +} + + +LONGBOW_TEST_CASE(Global, ccnxContentObject_SetSignature) +{ + CCNxName *name = ccnxName_CreateFromCString("ccnx:/hello/dolly"); + PARCBuffer *payload = parcBuffer_WrapCString("hello"); + + CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload); + + PARCBuffer *keyId = parcBuffer_WrapCString("keyhash"); + PARCBuffer *sigbits = parcBuffer_WrapCString("siggybits"); + PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, parcBuffer_Flip(sigbits)); + + ccnxContentObject_SetSignature(contentObject, keyId, signature, NULL); + + parcBuffer_Release(&payload); + parcBuffer_Release(&sigbits); + parcBuffer_Release(&keyId); + parcSignature_Release(&signature); + ccnxName_Release(&name); + ccnxContentObject_Release(&contentObject); +} + +LONGBOW_TEST_CASE(Global, ccnxContentObject_GetKeyId) +{ + CCNxName *name = ccnxName_CreateFromCString("ccnx:/hello/dolly"); + PARCBuffer *payload = parcBuffer_WrapCString("hello"); + + CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload); + + assertNull(ccnxContentObject_GetKeyId(contentObject), "Expect NULL for KeyId here"); + + PARCBuffer *testKeyId = parcBuffer_WrapCString("keyhash"); + PARCBuffer *sigbits = parcBuffer_WrapCString("siggybits"); + PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, parcBuffer_Flip(sigbits)); + + ccnxContentObject_SetSignature(contentObject, testKeyId, signature, NULL); + + PARCBuffer *keyId = ccnxContentObject_GetKeyId(contentObject); + + assertTrue(parcBuffer_Equals(keyId, testKeyId), "Expect key ids to match"); + + parcBuffer_Release(&payload); + parcBuffer_Release(&sigbits); + parcBuffer_Release(&keyId); + parcSignature_Release(&signature); + ccnxName_Release(&name); + ccnxContentObject_Release(&contentObject); +} + +LONGBOW_TEST_CASE(Global, ccnxContentObject_HasExpiryTime) +{ + CCNxName *name = ccnxName_CreateFromCString("ccnx:/hello/dolly"); + PARCBuffer *payload = parcBuffer_WrapCString("hello"); + + // Use a V1 ContentObject, as V0 doesn't support ExpiryTime + CCNxContentObject *contentObject = + ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation, + name, CCNxPayloadType_DATA, payload); + + + assertFalse(ccnxContentObject_HasExpiryTime(contentObject), "Expected no expiration time by default"); + + parcBuffer_Release(&payload); + ccnxName_Release(&name); + ccnxContentObject_Release(&contentObject); +} + +LONGBOW_TEST_CASE(Global, ccnxContentObject_SetGetExpiryTime) +{ + CCNxName *name = ccnxName_CreateFromCString("ccnx:/hello/dolly"); + PARCBuffer *payload = parcBuffer_WrapCString("hello"); + + // Use a V1 ContentObject, as V0 doesn't support ExpiryTime + CCNxContentObject *contentObject = + ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation, + name, CCNxPayloadType_DATA, payload); + + assertFalse(ccnxContentObject_HasExpiryTime(contentObject), "Expected no expiration time by default"); + + uint64_t expiryTime = 1010101ULL; + ccnxContentObject_SetExpiryTime(contentObject, expiryTime); + + assertTrue(ccnxContentObject_HasExpiryTime(contentObject), "Expected the expiryTime to be set"); + uint64_t retrievedTime = ccnxContentObject_GetExpiryTime(contentObject); + assertTrue(expiryTime == retrievedTime, "Did not retrieve expected expiryTime from ContentObject"); + + parcBuffer_Release(&payload); + ccnxName_Release(&name); + ccnxContentObject_Release(&contentObject); +} + +LONGBOW_TEST_CASE_EXPECTS(Global, ccnxContentObject_GetExpiryTimeWithNoExpiryTime, .event = &LongBowTrapUnexpectedStateEvent) +{ + CCNxName *name = ccnxName_CreateFromCString("ccnx:/hello/dolly"); + PARCBuffer *payload = parcBuffer_WrapCString("hello"); + + // Use a V1 ContentObject, as V0 doesn't support ExpiryTime + CCNxContentObject *contentObject = + ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation, + name, CCNxPayloadType_DATA, payload); + + // This should throw. + uint64_t retrievedTime = ccnxContentObject_GetExpiryTime(contentObject); + trapUnexpectedState("Expected to have thrown an exception when calling GetExpiryTime(), which returned %" PRIu64, retrievedTime); + parcBuffer_Release(&payload); + ccnxName_Release(&name); + ccnxContentObject_Release(&contentObject); +} + +LONGBOW_TEST_CASE(Global, ccnxContentObject_Display) +{ + CCNxName *name = ccnxName_CreateFromCString("ccnx:/hello/dolly"); + PARCBuffer *payload = parcBuffer_WrapCString("hello"); + + CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, payload); + + ccnxContentObject_Display(contentObject, 0); + + parcBuffer_Release(&payload); + ccnxName_Release(&name); + ccnxContentObject_Release(&contentObject); +} + +/////////////////////////////////////////////////////////////////////////// +// Empty Implementation Tests +/////////////////////////////////////////////////////////////////////////// + +LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetPayloadType, .event = &LongBowTrapNotImplemented) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.getPayloadType = NULL; + + CCNxPayloadType type = ccnxContentObject_GetPayloadType(data->contentObject); + printf("We shouldn't get here. Payload = %d", type); +} + +LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetPayload, .event = &LongBowTrapNotImplemented) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.getPayload = NULL; + + PARCBuffer *payload = ccnxContentObject_GetPayload(data->contentObject); + printf("We shouldn't get here. Payload = %p", (void *) payload); +} + +LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_SetPayload, .event = &LongBowTrapNotImplemented) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.setPayload = NULL; + + ccnxContentObject_SetPayload(data->contentObject, CCNxPayloadType_DATA, NULL); +} + +LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetName, .event = &LongBowTrapNotImplemented) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.getName = NULL; + + CCNxName *name = ccnxContentObject_GetName(data->contentObject); + printf("We shouldn't get here. Name = %p", (void *) name); +} + +LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_SetFinalChunkNumber, .event = &LongBowTrapNotImplemented) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.setFinalChunkNumber = NULL; + + ccnxContentObject_SetFinalChunkNumber(data->contentObject, 100); +} + +LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetFinalChunkNumber, .event = &LongBowTrapNotImplemented) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.getFinalChunkNumber = NULL; + + ccnxContentObject_SetFinalChunkNumber(data->contentObject, 100); + ccnxContentObject_GetFinalChunkNumber(data->contentObject); +} + +LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetFinalChunkNumberNoHas, .event = &LongBowTrapUnexpectedStateEvent) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.getFinalChunkNumber = NULL; + + ccnxContentObject_GetFinalChunkNumber(data->contentObject); +} + +LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_HasFinalChunkNumber, .event = &LongBowTrapNotImplemented) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.hasFinalChunkNumber = NULL; + + if (ccnxContentObject_HasFinalChunkNumber(data->contentObject)) { + printf("Shouldn't get here"); + } +} + +LONGBOW_TEST_CASE(EmptyImpl, empty_HasExpiryTime) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.hasExpiryTime = NULL; + + assertFalse(ccnxContentObject_HasExpiryTime(data->contentObject), "If no expiry time implementation, return false."); +} + +LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_SetExpiryTime, .event = &LongBowTrapNotImplemented) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.setExpiryTime = NULL; + + ccnxContentObject_SetExpiryTime(data->contentObject, 100); +} + +LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetExpiryTime, .event = &LongBowTrapNotImplemented) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.getExpiryTime = NULL; + + ccnxContentObject_SetExpiryTime(data->contentObject, 100); + uint64_t expiryTime = ccnxContentObject_GetExpiryTime(data->contentObject); + printf("We shouldn't get here, with expiryTime = %" PRIu64, expiryTime); +} + +LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetExpiryTimeNoHas, .event = &LongBowTrapUnexpectedStateEvent) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.getExpiryTime = NULL; + + uint64_t expiryTime = ccnxContentObject_GetExpiryTime(data->contentObject); + printf("We shouldn't get here, with expiryTime = %" PRIu64, expiryTime); +} + +LONGBOW_TEST_CASE(EmptyImpl, empty_Display) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.display = NULL; + + ccnxContentObject_Display(data->contentObject, 2); +} + +LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_ToString, .event = &LongBowTrapNotImplemented) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.toString = NULL; + + const char *expectedString = ccnxContentObject_ToString(data->contentObject); + if (expectedString != NULL) { + parcMemory_Deallocate((void **) &expectedString); + } +} + +LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_Equals, .event = &LongBowTrapNotImplemented) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.equals = NULL; + + if (ccnxContentObject_Equals(data->contentObject, data->contentObject)) { + printf("Shouldn't get here"); + } +} + +LONGBOW_TEST_FIXTURE(EmptyImpl) +{ + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_Display); + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_HasExpiryTime); + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetExpiryTime); + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetExpiryTimeNoHas); + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_SetExpiryTime); + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_SetFinalChunkNumber); + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetFinalChunkNumber); + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetFinalChunkNumberNoHas); + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_HasFinalChunkNumber); + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetPayload); + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetPayloadType); + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_SetPayload); + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetName); + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_ToString); + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_Equals); +} + +LONGBOW_TEST_FIXTURE_SETUP(EmptyImpl) +{ + longBowTestCase_SetClipBoardData(testCase, _commonSetup()); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(EmptyImpl) +{ + _commonTeardown(longBowTestCase_GetClipBoardData(testCase)); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_ContentObject); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/test/test_ccnx_Interest.c b/libccnx-common/ccnx/common/test/test_ccnx_Interest.c new file mode 100755 index 00000000..29debe9c --- /dev/null +++ b/libccnx-common/ccnx/common/test/test_ccnx_Interest.c @@ -0,0 +1,725 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ +#include <config.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include <ccnx/common/ccnx_Interest.c> + +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + +LONGBOW_TEST_RUNNER(ccnx_Interest) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(EmptyImpl); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnx_Interest) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_Interest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_Create); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_CreateSimple); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_Release); + + LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_AssertValid); + + LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_Equals_Same); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_Equals); + + LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_SetLifetime); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_GetLifetime); + + LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_GetName); + + LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_SetGetPayload); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_SetPayloadWithId); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_SetPayloadAndId); + + LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_SetGetHopLimit); + + LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_SetKeyIdRestriction); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_GetKeyIdRestriction); + + LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_GetContentObjectHashRestriction); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_SetContentObjectHashRestriction); + + LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_ToString); + + LONGBOW_RUN_TEST_CASE(Global, ccnxInterest_Display); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxInterest_Create) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/name"); + PARCBuffer *key = parcBuffer_Allocate(8); + parcBuffer_PutUint64(key, 1234L); + + CCNxInterest *interest = ccnxInterest_Create(name, + 15 * 1000, /* lifetime, 15 seconds in milliseconds */ + key, /* KeyId */ + NULL /* ContentObjectHash */ + ); + ccnxName_Release(&name); + parcBuffer_Release(&key); + ccnxInterest_Release(&interest); +} + +LONGBOW_TEST_CASE(Global, ccnxInterest_CreateSimple) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/name"); + CCNxInterest *interest = ccnxInterest_CreateSimple(name); + + ccnxName_Release(&name); + ccnxInterest_Release(&interest); +} + +LONGBOW_TEST_CASE(Global, ccnxInterest_Release) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/name"); + CCNxInterest *interest = ccnxInterest_CreateSimple(name); + + CCNxInterest *reference = ccnxInterest_Acquire(interest); + + ccnxName_Release(&name); + ccnxInterest_Release(&interest); + ccnxInterest_Release(&reference); + + assertNull(interest, "Expected ccnxInterest_Release to null the pointer."); + assertNull(reference, "Expected ccnxInterest_Release to null the pointer."); +} + +LONGBOW_TEST_CASE(Global, ccnxInterest_AssertValid) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie"); + CCNxInterest *interest = ccnxInterest_CreateSimple(name); + + ccnxInterest_AssertValid(interest); + + ccnxName_Release(&name); + ccnxInterest_Release(&interest); +} + +LONGBOW_TEST_CASE(Global, ccnxInterest_Equals_Same) +{ + CCNxName *nameA = ccnxName_CreateFromCString("lci:/name"); + PARCBuffer *key = parcBuffer_Allocate(8); + parcBuffer_PutUint64(key, 1234L); + + CCNxInterest *interestA = ccnxInterest_Create(nameA, + CCNxInterestDefault_LifetimeMilliseconds, /* lifetime */ + key, /* KeyId */ + NULL /* ContentObjectHash */ + ); + + assertTrue(ccnxInterest_Equals(interestA, interestA), "Expected the same interest to be equal."); + + assertFalse(ccnxInterest_Equals(interestA, NULL), "Did not expect NULL to equal an Interest"); + + + ccnxName_Release(&nameA); + parcBuffer_Release(&key); + ccnxInterest_Release(&interestA); +} + +LONGBOW_TEST_CASE(Global, ccnxInterest_Equals) +{ + CCNxName *nameA = ccnxName_CreateFromCString("lci:/name"); + PARCBuffer *keyA = parcBuffer_Allocate(8); + parcBuffer_PutUint64(keyA, 1234L); + + CCNxInterest *interestA = ccnxInterest_Create(nameA, + 1000, /* lifetime */ + keyA, /* KeyId */ + NULL /* ContentObjectHash */ + ); + + CCNxName *nameB = ccnxName_CreateFromCString("lci:/name"); + PARCBuffer *keyB = parcBuffer_Allocate(8); + parcBuffer_PutUint64(keyB, 1234L); + CCNxInterest *interestB = ccnxInterest_Create(nameB, + 1000, /* lifetime */ + keyB, /* KeyId */ + NULL /* ContentObjectHash */ + ); + + assertTrue(ccnxInterest_Equals(interestA, interestB), "Expected equivalent interests to be equal."); + + ccnxName_Release(&nameA); + ccnxName_Release(&nameB); + parcBuffer_Release(&keyA); + parcBuffer_Release(&keyB); + ccnxInterest_Release(&interestA); + ccnxInterest_Release(&interestB); +} + +LONGBOW_TEST_CASE(Global, ccnxInterest_SetLifetime) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/name"); + PARCBuffer *key = parcBuffer_Allocate(8); + parcBuffer_PutUint64(key, 1234L); + + uint32_t lifetime = 5000; // 5 seconds, in milliseconds + + CCNxInterest *interest = ccnxInterest_Create(name, + lifetime, /* lifetime */ + key, /* KeyId */ + NULL /* ContentObjectHash */ + ); + + uint32_t actual = ccnxInterest_GetLifetime(interest); + + assertTrue(actual == lifetime, "Expected the retrieved lifetime to be equal to the assigned one."); + + lifetime = 2000; + ccnxInterest_SetLifetime(interest, lifetime); + actual = ccnxInterest_GetLifetime(interest); + + assertTrue(actual == lifetime, "Expected the retrieved lifetime to be equal to the assigned one."); + + ccnxName_Release(&name); + parcBuffer_Release(&key); + ccnxInterest_Release(&interest); +} + + +LONGBOW_TEST_CASE(Global, ccnxInterest_GetLifetime) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/name"); + PARCBuffer *key = parcBuffer_Allocate(8); + parcBuffer_PutUint64(key, 1234L); + + uint32_t lifetime = 5000; // 5 seconds, in milliseconds + + CCNxInterest *interest = ccnxInterest_Create(name, + lifetime, /* lifetime */ + key, /* KeyId */ + NULL /* ContentObjectHash */ + ); + + uint32_t actual = ccnxInterest_GetLifetime(interest); + + assertTrue(actual == lifetime, "Expected the retrieved lifetime to be equal to the assigned one."); + + ccnxName_Release(&name); + parcBuffer_Release(&key); + ccnxInterest_Release(&interest); +} + +LONGBOW_TEST_CASE(Global, ccnxInterest_GetName) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/name"); + CCNxInterest *interest = ccnxInterest_CreateSimple(name); + + CCNxName *actual = ccnxInterest_GetName(interest); + assertTrue(ccnxName_Equals(name, actual), "Expected the same name."); + + ccnxName_Release(&name); + ccnxInterest_Release(&interest); +} + +LONGBOW_TEST_CASE(Global, ccnxInterest_SetKeyIdRestriction) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/name"); + PARCBuffer *key = parcBuffer_Allocate(8); + parcBuffer_PutUint64(key, 1234L); + + CCNxInterest *interest = ccnxInterest_Create(name, 3000, NULL, NULL); + ccnxInterest_SetKeyIdRestriction(interest, key); + PARCBuffer *actual = ccnxInterest_GetKeyIdRestriction(interest); + + actual = ccnxInterest_GetKeyIdRestriction(interest); + assertTrue(actual == key, "Expected retrieved key to be the same as assigned"); + + ccnxName_Release(&name); + ccnxInterest_Release(&interest); + parcBuffer_Release(&key); +} + +LONGBOW_TEST_CASE(Global, ccnxInterest_GetKeyIdRestriction) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/name"); + PARCBuffer *key = parcBuffer_Allocate(8); + parcBuffer_PutUint64(key, 1234L); + + CCNxInterest *interest = ccnxInterest_Create(name, 3000, key, NULL); + + PARCBuffer *actual = ccnxInterest_GetKeyIdRestriction(interest); + + actual = ccnxInterest_GetKeyIdRestriction(interest); + assertTrue(actual == key, "Expected retrieved key to be the same as assigned"); + + ccnxName_Release(&name); + ccnxInterest_Release(&interest); + parcBuffer_Release(&key); +} + +LONGBOW_TEST_CASE(Global, ccnxInterest_SetContentObjectHashRestriction) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/name"); + PARCBuffer *coh = parcBuffer_Allocate(8); + parcBuffer_PutUint64(coh, 77573L); + + CCNxInterest *interest = ccnxInterest_Create(name, CCNxInterestDefault_LifetimeMilliseconds, NULL, NULL); + + PARCBuffer *actual = ccnxInterest_GetContentObjectHashRestriction(interest); + assertNull(actual, "Expected retrieved ContentObjectHash to be initially NULL"); + + ccnxInterest_SetContentObjectHashRestriction(interest, coh); + actual = ccnxInterest_GetContentObjectHashRestriction(interest); + + assertTrue(actual == coh, "Expected retrieved ContentObjectHash to be the same as assigned"); + + // Re-setting is not yet supported. At the moment, you can only put the COHR once. + // Now change it, and validate. + //PARCBuffer *coh2 = parcBuffer_Allocate(8); + //parcBuffer_PutUint64(coh2, 3262L); + //ccnxInterest_SetContentObjectHashRestriction(interest, coh2); + //actual = ccnxInterest_GetContentObjectHashRestriction(interest); + //assertTrue(actual == coh2, "Expected retrieved ContentObjectHash to be the same as assigned"); + + ccnxName_Release(&name); + ccnxInterest_Release(&interest); + parcBuffer_Release(&coh); + //parcBuffer_Release(&coh2); +} + +LONGBOW_TEST_CASE(Global, ccnxInterest_GetContentObjectHashRestriction) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/name"); + PARCBuffer *coh = parcBuffer_Allocate(8); + parcBuffer_PutUint64(coh, 1234L); + + CCNxInterest *interest = ccnxInterest_Create(name, CCNxInterestDefault_LifetimeMilliseconds, NULL, coh); + + PARCBuffer *actual = ccnxInterest_GetContentObjectHashRestriction(interest); + + assertTrue(actual == coh, "Expected retrieved ContentObjectHash to be the same as assigned"); + + ccnxName_Release(&name); + ccnxInterest_Release(&interest); + parcBuffer_Release(&coh); +} + +LONGBOW_TEST_CASE(Global, ccnxInterest_SetGetPayload) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/name"); + CCNxInterest *interest = ccnxInterest_CreateSimple(name); + CCNxName *origNameCopy = ccnxName_Copy(name); + + CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest); + + if (impl->getPayload) { + assertNull(ccnxInterest_GetPayload(interest), "Expected a NULL payload"); + } + + if (impl->getPayload && impl->setPayload) { + PARCBuffer *payload = parcBuffer_WrapCString("impls have pimples"); + ccnxInterest_SetPayload(interest, payload); + + PARCBuffer *payloadOut = ccnxInterest_GetPayload(interest); + + assertTrue(parcBuffer_Equals(payload, payloadOut), "Expected an equal buffer"); + + CCNxName *nameAfterPayload = ccnxInterest_GetName(interest); + assertTrue(ccnxName_Equals(nameAfterPayload, origNameCopy), "Expected an unmodified name"); + + parcBuffer_Release(&payload); + } + ccnxName_Release(&name); + ccnxName_Release(&origNameCopy); + ccnxInterest_Release(&interest); +} + +LONGBOW_TEST_CASE(Global, ccnxInterest_SetPayloadAndId) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/name"); + CCNxInterest *interest = ccnxInterest_CreateSimple(name); + + CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest); + + if (impl->getPayload) { + assertNull(ccnxInterest_GetPayload(interest), "Expected a NULL payload"); + } + + if (impl->getPayload && impl->setPayload) { + PARCBuffer *payload = parcBuffer_WrapCString("impls have pimples"); + + ccnxInterest_SetPayloadAndId(interest, payload); + + PARCBuffer *payloadOut = ccnxInterest_GetPayload(interest); + + assertTrue(parcBuffer_Equals(payload, payloadOut), "Expected an equal buffer"); + + CCNxName *nameAfterPayload = ccnxInterest_GetName(interest); + CCNxNameSegment *segment = ccnxName_GetSegment(nameAfterPayload, ccnxName_GetSegmentCount(nameAfterPayload) - 1); + + assertTrue(ccnxNameSegment_GetType(segment) == CCNxNameLabelType_PAYLOADID, "Expected to find a payload ID appended to the name"); + + parcBuffer_Release(&payload); + } + ccnxName_Release(&name); + ccnxInterest_Release(&interest); +} + +LONGBOW_TEST_CASE(Global, ccnxInterest_SetPayloadWithId) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/name"); + CCNxInterest *interest = ccnxInterest_CreateSimple(name); + CCNxName *origNameCopy = ccnxName_Copy(name); + + CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest); + + if (impl->getPayload) { + assertNull(ccnxInterest_GetPayload(interest), "Expected a NULL payload"); + } + + if (impl->getPayload && impl->setPayload) { + PARCBuffer *payload = parcBuffer_WrapCString("impls have pimples"); + PARCBuffer *payloadIdBuffer = parcBuffer_WrapCString("payload Id buffer"); + + CCNxInterestPayloadId *payloadId = ccnxInterestPayloadId_Create(payloadIdBuffer, + CCNxInterestPayloadId_TypeCode_App + 2); + + ccnxInterest_SetPayloadWithId(interest, payload, payloadId); + + PARCBuffer *payloadOut = ccnxInterest_GetPayload(interest); + + assertTrue(parcBuffer_Equals(payload, payloadOut), "Expected an equal buffer"); + + CCNxName *nameAfterPayload = ccnxInterest_GetName(interest); + CCNxNameSegment *segment = ccnxName_GetSegment(nameAfterPayload, ccnxName_GetSegmentCount(nameAfterPayload) - 1); + + assertTrue(ccnxNameSegment_GetType(segment) == CCNxNameLabelType_PAYLOADID, "Expected to find a payload ID appended to the name"); + + CCNxInterestPayloadId *outId = ccnxInterestPayloadId_CreateFromSegmentInName(nameAfterPayload); + assertTrue(ccnxInterestPayloadId_Equals(outId, payloadId), "expected to see the same payload Id after setting the payload"); + + ccnxInterestPayloadId_Release(&payloadId); + ccnxInterestPayloadId_Release(&outId); + + parcBuffer_Release(&payload); + parcBuffer_Release(&payloadIdBuffer); + } + ccnxName_Release(&name); + ccnxName_Release(&origNameCopy); + ccnxInterest_Release(&interest); +} + + +LONGBOW_TEST_CASE(Global, ccnxInterest_SetGetHopLimit) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/name"); + CCNxInterest *interest = ccnxInterest_CreateSimple(name); + + CCNxInterestInterface *impl = ccnxInterestInterface_GetInterface(interest); + + if (impl->getHopLimit) { + assertTrue(ccnxInterest_GetHopLimit(interest) == CCNxInterestDefault_HopLimit, "Expected the default hop limit"); + } + + if (impl->setHopLimit && impl->getHopLimit) { + ccnxInterest_SetHopLimit(interest, 10); + assertTrue(ccnxInterest_GetHopLimit(interest) == 10, "Expected a hopLimit of 10"); + ccnxInterest_SetHopLimit(interest, 20); + assertTrue(ccnxInterest_GetHopLimit(interest) == 20, "Expected a hopLimit of 20"); + } + + ccnxName_Release(&name); + ccnxInterest_Release(&interest); +} + +LONGBOW_TEST_CASE(Global, ccnxInterest_ToString) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/name"); + CCNxInterest *interest = ccnxInterest_Create(name, + CCNxInterestDefault_LifetimeMilliseconds, /* lifetime */ + NULL, /* KeyId */ + NULL /* ContentObjectHash */ + ); + + const char *expectedString = ccnxInterest_ToString(interest); + assertNotNull(expectedString, "Expected non-null result from ccnxInterest_ToString."); + + parcMemory_Deallocate((void **) &expectedString); + ccnxName_Release(&name); + ccnxInterest_Release(&interest); +} + +LONGBOW_TEST_CASE(Global, ccnxInterest_Display) +{ + PARCBuffer *coh = parcBuffer_Allocate(8); + parcBuffer_PutUint64(coh, 7778L); + + CCNxName *name = ccnxName_CreateFromCString("lci:/name"); + CCNxInterest *interest = ccnxInterest_Create(name, + 100, /* lifetime */ + NULL, /* KeyId */ + coh); /* ContentObjectHash */ + + ccnxInterest_Display(interest, 2); + ccnxName_Release(&name); + ccnxInterest_Release(&interest); + parcBuffer_Release(&coh); +} + +/////////////////////////////////////////////////////////////////////////////// +// Empty Implementation tests +/////////////////////////////////////////////////////////////////////////////// + + +typedef struct test_data { + CCNxInterestInterface impl; + CCNxName *name; + CCNxInterest *interest; +} TestData; + + +static TestData * +_commonSetup(void) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + + CCNxName *name = ccnxName_CreateFromCString("lci:/default/testData/content"); + + data->impl = CCNxInterestFacadeV1_Implementation; // This copies the struct each time. + data->name = name; + data->interest = ccnxInterest_CreateWithImpl(&data->impl, name, 100, NULL, NULL, 10); + + return data; +} + +static void +_commonTeardown(TestData *data) +{ + if (data->interest) { + ccnxInterest_Release(&data->interest); + } + if (data->name) { + ccnxName_Release(&data->name); + } + + parcMemory_Deallocate((void **) &data); +} + +LONGBOW_TEST_FIXTURE_SETUP(EmptyImpl) +{ + longBowTestCase_SetClipBoardData(testCase, _commonSetup()); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(EmptyImpl) +{ + _commonTeardown(longBowTestCase_GetClipBoardData(testCase)); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + + +LONGBOW_TEST_CASE(EmptyImpl, empty_Display) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.display = NULL; + + ccnxInterest_Display(data->interest, 2); +} + +LONGBOW_TEST_CASE(EmptyImpl, empty_ToString) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.toString = NULL; + + const char *expectedString = ccnxInterest_ToString(data->interest); + if (expectedString != NULL) { + parcMemory_Deallocate((void **) &expectedString); + } +} + +LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetName, .event = &LongBowTrapNotImplemented) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.getName = NULL; + + CCNxName *name = ccnxInterest_GetName(data->interest); + printf("Shouldn't get here. name = %p\n", (void *) name); +} + +LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_SetHopLimit, .event = &LongBowTrapNotImplemented) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.setHopLimit = NULL; + + if (ccnxInterest_SetHopLimit(data->interest, 10)) { + printf("Shouldn't get here"); + } +} + +LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetHopLimit, .event = &LongBowTrapNotImplemented) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.getHopLimit = NULL; + + uint32_t hopLimit = ccnxInterest_GetHopLimit(data->interest); + printf("Shouldn't get here. hopLimit = %u\n", hopLimit); +} + +LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_SetLifetime, .event = &LongBowTrapNotImplemented) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.setLifetime = NULL; + + if (ccnxInterest_SetLifetime(data->interest, 10)) { + printf("Shouldn't get here"); + } +} + +LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetLifetime, .event = &LongBowTrapNotImplemented) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.getLifetime = NULL; + + uint32_t lifetime = ccnxInterest_GetLifetime(data->interest); + printf("Shouldn't get here. lifetime = %u\n", lifetime); +} + +LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_SetKeyIdRestriction, .event = &LongBowTrapNotImplemented) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.setKeyIdRestriction = NULL; + + if (ccnxInterest_SetKeyIdRestriction(data->interest, NULL)) { + printf("Shouldn't get here"); + } +} + +LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetKeyIdRestriction, .event = &LongBowTrapNotImplemented) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.getKeyIdRestriction = NULL; + + PARCBuffer *keyIdRestriction = ccnxInterest_GetKeyIdRestriction(data->interest); + printf("Shouldn't get here. getKeyIdRestriction = %p\n", (void *) keyIdRestriction); +} + +LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_SetContentObjectHashRestriction, .event = &LongBowTrapNotImplemented) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.setContentObjectHashRestriction = NULL; + + if (ccnxInterest_SetContentObjectHashRestriction(data->interest, NULL)) { + printf("Shouldn't get here"); + } +} + +LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetContentObjectHashRestriction, .event = &LongBowTrapNotImplemented) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.getContentObjectHashRestriction = NULL; + + PARCBuffer *restriction = ccnxInterest_GetContentObjectHashRestriction(data->interest); + printf("Shouldn't get here. restriction = %p\n", (void *) restriction); +} + +LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_SetPayload, .event = &LongBowTrapNotImplemented) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.setPayload = NULL; + + if (ccnxInterest_SetPayload(data->interest, NULL)) { + printf("Shouldn't get here"); + } +} + +LONGBOW_TEST_CASE_EXPECTS(EmptyImpl, empty_GetPayload, .event = &LongBowTrapNotImplemented) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + data->impl.getPayload = NULL; + + PARCBuffer *payload = ccnxInterest_GetPayload(data->interest); + printf("Shouldn't get here. payload = %p\n", (void *) payload); +} + +LONGBOW_TEST_FIXTURE(EmptyImpl) +{ + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_Display); + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_ToString); + + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetName); + + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetHopLimit); + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_SetHopLimit); + + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetLifetime); + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_SetLifetime); + + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetKeyIdRestriction); + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_SetKeyIdRestriction); + + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetContentObjectHashRestriction); + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_SetContentObjectHashRestriction); + + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_GetPayload); + LONGBOW_RUN_TEST_CASE(EmptyImpl, empty_SetPayload); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_Interest); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/test/test_ccnx_InterestPayloadId.c b/libccnx-common/ccnx/common/test/test_ccnx_InterestPayloadId.c new file mode 100755 index 00000000..28e07643 --- /dev/null +++ b/libccnx-common/ccnx/common/test/test_ccnx_InterestPayloadId.c @@ -0,0 +1,469 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include <config.h> + +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> +#include <stdio.h> + +#include "../ccnx_InterestPayloadId.c" + +static const PARCMemoryInterface *_originalMemoryProvider; + +LONGBOW_TEST_RUNNER(ccnx_InterestPayloadId) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Error); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnx_InterestPayloadId) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_InterestPayloadId) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_CreateWithAppDefinedType); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_CreateAsCryptoHash); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_CreateFromSegmentInName); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_CreateFromSegmentInName_NotFound); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_Acquire); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_GetNameSegment); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_GetValue); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_GetType); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_IsValid); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_ToString); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_Copy); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_Equals); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_NotEquals); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_Compare); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestPayloadId_HashCode); +} + +typedef struct { + uint8_t type; + PARCBuffer *value; +} TestData; + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + data->value = parcBuffer_WrapCString("123456789abcdef"); + data->type = 42 + CCNxInterestPayloadId_TypeCode_App; + longBowTestCase_SetClipBoardData(testCase, data); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + parcBuffer_Release(&data->value); + parcMemory_Deallocate((void **) &data); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + parcMemory_SetInterface(_originalMemoryProvider); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_CreateWithAppDefinedType) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + uint8_t type = data->type; + PARCBuffer *value = parcBuffer_Acquire(data->value); + CCNxInterestPayloadId *ipId = ccnxInterestPayloadId_Create(value, type); + assertNotNull(ipId, "Expect a non-NULL result from Create"); + ccnxInterestPayloadId_AssertValid(ipId); + + parcBuffer_Release(&value); + + assertTrue(ccnxInterestPayloadId_IsValid(ipId), "Expected a valid CCNxInteresPayloadId."); + ccnxInterestPayloadId_Release(&ipId); +} + + +LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_CreateAsCryptoHash) +{ + PARCBuffer *value = parcBuffer_WrapCString("123456789abcdef"); + CCNxInterestPayloadId *ipId = ccnxInterestPayloadId_CreateAsSHA256Hash(value); + assertNotNull(ipId, "Expect a non-NULL result from CreateByHash"); + ccnxInterestPayloadId_AssertValid(ipId); + + parcBuffer_Release(&value); + + assertTrue(ccnxInterestPayloadId_IsValid(ipId), "Expected a valid CCNxInteresPayloadId."); + ccnxInterestPayloadId_Release(&ipId); +} + +LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_CreateFromSegmentInName) +{ + PARCBuffer *value = parcBuffer_WrapCString("123456789abcdef"); + CCNxInterestPayloadId *ipId = ccnxInterestPayloadId_CreateAsSHA256Hash(value); + parcBuffer_Release(&value); + assertNotNull(ipId, "Expect a non-NULL result from CreateByHash"); + ccnxInterestPayloadId_AssertValid(ipId); + assertTrue(ccnxInterestPayloadId_IsValid(ipId), "Expected a valid CCNxInteresPayloadId."); + + CCNxName *name = ccnxName_CreateFromCString("lci:/segment1/segment2/segment3"); + ccnxName_Append(name, ccnxInterestPayloadId_GetNameSegment(ipId)); + + CCNxInterestPayloadId *result = ccnxInterestPayloadId_CreateFromSegmentInName(name); + ccnxName_Release(&name); + + assertNotNull(result, "Should have found a payload ID"); + ccnxInterestPayloadId_AssertValid(result); + + assertTrue(ccnxInterestPayloadId_Equals(result, ipId), + "Expected source and result Interest Payload IDs to be equal"); + + ccnxInterestPayloadId_Release(&ipId); + ccnxInterestPayloadId_Release(&result); +} + +LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_CreateFromSegmentInName_NotFound) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/segment1/segment2/segment3"); + CCNxInterestPayloadId *result = ccnxInterestPayloadId_CreateFromSegmentInName(name); + ccnxName_Release(&name); + + assertNull(result, "Should have not found a payload ID"); +} + +LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_Acquire) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + uint8_t type = data->type; + PARCBuffer *value = parcBuffer_Acquire(data->value); + CCNxInterestPayloadId *ipId = ccnxInterestPayloadId_Create(value, type); + parcBuffer_Release(&value); + ccnxInterestPayloadId_AssertValid(ipId); + + CCNxInterestPayloadId *ipIdAcq = ccnxInterestPayloadId_Acquire(ipId); + ccnxInterestPayloadId_AssertValid(ipIdAcq); + + ccnxInterestPayloadId_Release(&ipId); + ccnxInterestPayloadId_Release(&ipIdAcq); +} + +LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_GetValue) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + uint8_t type = data->type; + PARCBuffer *value = parcBuffer_Acquire(data->value); + CCNxInterestPayloadId *ipId = ccnxInterestPayloadId_Create(value, type); + ccnxInterestPayloadId_AssertValid(ipId); + + assertTrue(parcBuffer_Equals(ccnxInterestPayloadId_GetValue(ipId), value), + "Expect GetId to produce the correct result"); + + parcBuffer_Release(&value); + ccnxInterestPayloadId_Release(&ipId); +} + +LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_GetType) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + uint8_t type = data->type; + PARCBuffer *value = parcBuffer_Acquire(data->value); + CCNxInterestPayloadId *ipId = ccnxInterestPayloadId_Create(value, type); + ccnxInterestPayloadId_AssertValid(ipId); + + assertTrue(ccnxInterestPayloadId_GetType(ipId) == type, + "Expect GetId to produce the correct result"); + + parcBuffer_Release(&value); + ccnxInterestPayloadId_Release(&ipId); +} + +LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_GetType_App) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + uint8_t type = data->type; + PARCBuffer *value = parcBuffer_Acquire(data->value); + CCNxInterestPayloadId *ipId = ccnxInterestPayloadId_Create(value, type); + ccnxInterestPayloadId_AssertValid(ipId); + + assertTrue(parcBuffer_Equals(ccnxInterestPayloadId_GetValue(ipId), value), + "Expect GetId to produce the correct result"); + + parcBuffer_Release(&value); + ccnxInterestPayloadId_Release(&ipId); +} + +LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_HashCode) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + uint8_t type = data->type; + PARCBuffer *value = parcBuffer_Acquire(data->value); + CCNxInterestPayloadId *ipId1 = ccnxInterestPayloadId_Create(value, type); + uint32_t hashCode1 = ccnxInterestPayloadId_HashCode(ipId1); + CCNxInterestPayloadId *ipId2 = ccnxInterestPayloadId_Create(value, type); + uint32_t hashCode2 = ccnxInterestPayloadId_HashCode(ipId2); + assertTrue(hashCode1 == hashCode2, "Expect hash codes of equal objects to be equal"); + parcBuffer_Release(&value); + ccnxInterestPayloadId_Release(&ipId1); + ccnxInterestPayloadId_Release(&ipId2); +} + + +LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_Equals) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + uint8_t type = data->type; + PARCBuffer *value = parcBuffer_WrapCString("123456789abcdef"); + CCNxInterestPayloadId *ipId = ccnxInterestPayloadId_Create(value, type); + ccnxInterestPayloadId_AssertValid(ipId); + + PARCBuffer *value2 = parcBuffer_WrapCString("123456789abcdef"); + CCNxInterestPayloadId *ipId2 = ccnxInterestPayloadId_Create(value2, type); + ccnxInterestPayloadId_AssertValid(ipId2); + + assertTrue(ccnxInterestPayloadId_Equals(ipId, ipId2), + "Expect InterestPayloadIds to be equal"); + + CCNxInterestPayloadId *ipId3 = ccnxInterestPayloadId_Create(value, type); + ccnxInterestPayloadId_AssertValid(ipId3); + + assertTrue(ccnxInterestPayloadId_Equals(ipId, ipId3), + "Expect InterestPayloadIds to be equal"); + + parcBuffer_Release(&value); + parcBuffer_Release(&value2); + ccnxInterestPayloadId_Release(&ipId); + ccnxInterestPayloadId_Release(&ipId2); + ccnxInterestPayloadId_Release(&ipId3); +} + +LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_NotEquals) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + uint8_t type = data->type; + PARCBuffer *value = parcBuffer_WrapCString("123456789abcdef"); + CCNxInterestPayloadId *ipId = ccnxInterestPayloadId_Create(value, type); + ccnxInterestPayloadId_AssertValid(ipId); + + PARCBuffer *value2 = parcBuffer_WrapCString("123456789abcdex"); + CCNxInterestPayloadId *ipId2 = ccnxInterestPayloadId_Create(value2, type); + ccnxInterestPayloadId_AssertValid(ipId2); + + assertTrue(!ccnxInterestPayloadId_Equals(ipId, ipId2), + "Expect InterestPayloadIds to be equal"); + + parcBuffer_Release(&value); + parcBuffer_Release(&value2); + ccnxInterestPayloadId_Release(&ipId); + ccnxInterestPayloadId_Release(&ipId2); +} + + +LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_Compare) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + uint8_t type = data->type; + PARCBuffer *value1 = parcBuffer_WrapCString("123456789abcdef"); + CCNxInterestPayloadId *ipId1 = ccnxInterestPayloadId_Create(value1, type); + ccnxInterestPayloadId_AssertValid(ipId1); + + assertTrue(ccnxInterestPayloadId_Compare(ipId1, ipId1) == 0, + "Expect compare result of 0 when comparing InterestPayloadId to itself"); + + PARCBuffer *value1p = parcBuffer_WrapCString("123456789abcdef"); + CCNxInterestPayloadId *ipId1p = ccnxInterestPayloadId_Create(value1p, type); + ccnxInterestPayloadId_AssertValid(ipId1p); + + assertTrue(ccnxInterestPayloadId_Compare(ipId1, ipId1p) == 0, + "Expect compare result of 0 when comparing InterestPayloadIds with the same content"); + + PARCBuffer *value2 = parcBuffer_WrapCString("123456789abcdex"); + CCNxInterestPayloadId *ipId2 = ccnxInterestPayloadId_Create(value2, type); + ccnxInterestPayloadId_AssertValid(ipId2); + + assertTrue(ccnxInterestPayloadId_Compare(ipId2, ipId1) > 0, + "Expect compare result > 0 when comparing InterestPayloadId2 to InterestPayloadId1"); + + parcBuffer_Release(&value1); + parcBuffer_Release(&value1p); + parcBuffer_Release(&value2); + + ccnxInterestPayloadId_Release(&ipId1); + ccnxInterestPayloadId_Release(&ipId1p); + ccnxInterestPayloadId_Release(&ipId2); +} + +LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_Copy) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + uint8_t type = data->type; + PARCBuffer *value1 = parcBuffer_Acquire(data->value); + CCNxInterestPayloadId *ipId1 = ccnxInterestPayloadId_Create(value1, type); + parcBuffer_Release(&value1); + ccnxInterestPayloadId_AssertValid(ipId1); + + CCNxInterestPayloadId *ipIdCopy = ccnxInterestPayloadId_Copy(ipId1); + ccnxInterestPayloadId_AssertValid(ipIdCopy); + assertTrue(ccnxInterestPayloadId_Equals(ipId1, ipIdCopy), "Expect original and copy InterestPayloadId to be equal"); + + ccnxInterestPayloadId_Release(&ipId1); + ccnxInterestPayloadId_Release(&ipIdCopy); +} + +LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_IsValid) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + uint8_t type = data->type; + PARCBuffer *value = parcBuffer_Acquire(data->value); + CCNxInterestPayloadId *ipId = ccnxInterestPayloadId_Create(value, type); + parcBuffer_Release(&value); + + assertTrue(ccnxInterestPayloadId_IsValid(ipId), "Expected a valid CCNxInteresPayloadId."); + ccnxInterestPayloadId_Release(&ipId); +} + +LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_ToString) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + uint8_t type = data->type; + char *test = "123456789abcdef"; + PARCBuffer *value = parcBuffer_WrapCString(test); + CCNxInterestPayloadId *ipId = ccnxInterestPayloadId_Create(value, type); + parcBuffer_Release(&value); + + char *result = ccnxInterestPayloadId_ToString(ipId); + assertNotNull(result, "Expect a non-NULL result from ToString"); + ccnxInterestPayloadId_Release(&ipId); + + PARCBufferComposer *composer = parcBufferComposer_Allocate(10); + parcBufferComposer_PutString(composer, CCNxNameLabel_InterestPayloadId); + parcBufferComposer_PutChar(composer, '='); + + PARCBufferComposer *uriComposer = parcBufferComposer_Allocate(10); + parcBufferComposer_PutChar(uriComposer, type); + parcBufferComposer_PutString(uriComposer, test); + PARCBuffer *producedBuffer = parcBufferComposer_ProduceBuffer(uriComposer); + PARCURISegment *uriSegment = parcURISegment_CreateFromBuffer(producedBuffer); + parcBuffer_Release(&producedBuffer); + parcBufferComposer_Release(&uriComposer); + parcURISegment_BuildString(uriSegment, composer); + parcURISegment_Release(&uriSegment); + char *expect = parcBufferComposer_ToString(composer); + parcBufferComposer_Release(&composer); + + assertTrue(strcmp(expect, result) == 0, "Expect test and result strings to be the same."); + + parcMemory_Deallocate((void **) &result); + parcMemory_Deallocate((void **) &expect); +} + +LONGBOW_TEST_CASE(Global, ccnxInterestPayloadId_GetNameSegment) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + uint8_t type = data->type; + PARCBuffer *value = parcBuffer_Acquire(data->value); + CCNxInterestPayloadId *ipId = ccnxInterestPayloadId_Create(value, type); + + CCNxNameSegment *segment = ccnxNameSegment_Acquire(ccnxInterestPayloadId_GetNameSegment(ipId)); + ccnxInterestPayloadId_Release(&ipId); + + PARCBufferComposer *composer = parcBufferComposer_Allocate(parcBuffer_Capacity(value) + 1); + parcBufferComposer_PutUint8(composer, type); + parcBufferComposer_PutBuffer(composer, value); + PARCBuffer *testValue = parcBufferComposer_ProduceBuffer(composer); + parcBufferComposer_Release(&composer); + parcBuffer_Release(&value); + CCNxNameSegment *testSegment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_PAYLOADID, testValue); + parcBuffer_Release(&testValue); + assertTrue(ccnxNameSegment_Equals(segment, testSegment), "Expect GetAsNameSegment result to match test NameSegment"); + + ccnxNameSegment_Release(&segment); + ccnxNameSegment_Release(&testSegment); +} + +LONGBOW_TEST_FIXTURE(Error) +{ + LONGBOW_RUN_TEST_CASE(Error, ccnxInterestPayloadId__CreateFromNameSegment_NotFound); +} + +typedef struct { + CCNxName *name; +} TestDataError; + +LONGBOW_TEST_FIXTURE_SETUP(Error) +{ + _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + + + TestDataError *data = parcMemory_AllocateAndClear(sizeof(TestDataError)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataError)); + data->name = ccnxName_CreateFromCString("lci:/segment1/segment2/segment3"); + longBowTestCase_SetClipBoardData(testCase, data); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Error) +{ + TestDataError *data = longBowTestCase_GetClipBoardData(testCase); + ccnxName_Release(&data->name); + parcMemory_Deallocate((void **) &data); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + parcMemory_SetInterface(_originalMemoryProvider); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE_EXPECTS(Error, ccnxInterestPayloadId__CreateFromNameSegment_NotFound, .event = &LongBowAssertEvent) +{ + TestDataError *data = longBowTestCase_GetClipBoardData(testCase); + CCNxNameSegment *nameSegment = ccnxName_GetSegment(data->name, 0); + CCNxInterestPayloadId *result = + _ccnxInterestPayloadId_CreateFromNameSegment(nameSegment); + assertNull(result, "Expect an assert event or NULL"); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_InterestPayloadId); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/test/test_ccnx_InterestReturn.c b/libccnx-common/ccnx/common/test/test_ccnx_InterestReturn.c new file mode 100755 index 00000000..79e27994 --- /dev/null +++ b/libccnx-common/ccnx/common/test/test_ccnx_InterestReturn.c @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnx_InterestReturn.c" +#include "../ccnx_Interest.h" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +#include <ccnx/common/ccnx_Interest.h> +#include <ccnx/common/ccnx_InterestReturn.h> +#include <ccnx/common/ccnx_PayloadType.h> + +typedef struct test_data { + CCNxTlvDictionary *interest; + CCNxInterestInterface *interestImpl; + + CCNxName *name; + PARCBuffer *keyid; + PARCBuffer *contentObjectHash; + PARCBuffer *payload; + + // allocated data + uint8_t keyidArray[32]; + uint8_t contentObjectHashArray[32]; + uint8_t payloadArray[128]; + + uint32_t lifetime; + uint32_t hoplimit; + CCNxPayloadType payloadType; +} TestData; + + +LONGBOW_TEST_RUNNER(ccnx_InterestReturnV1) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnx_InterestReturnV1) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_InterestReturnV1) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ======================================================================================== + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestReturnV1_Create); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestReturnV1_GetReturnCode); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestReturnV1_AcquireRelease); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestReturnV1_Equals); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestReturnV1_NotEquals); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestReturnV1_ToString); + LONGBOW_RUN_TEST_CASE(Global, ccnxInterestReturnV1_GetInterestFields); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%lu) returned NULL", sizeof(TestData)); + data->name = ccnxName_CreateFromCString("lci:/once/upon/a/time"); + + for (int i = 0; i < 32; i++) { + data->keyidArray[i] = i * 7; + data->contentObjectHashArray[i] = i * 11; + } + + for (int i = 0; i < 128; i++) { + data->payloadArray[i] = i * 13; + } + + data->interestImpl = &CCNxInterestFacadeV1_Implementation; + data->keyid = parcBuffer_Wrap(data->keyidArray, 32, 0, 32); + data->contentObjectHash = parcBuffer_Wrap(data->contentObjectHashArray, 32, 0, 32); + data->payloadType = CCNxPayloadType_DATA; + data->payload = parcBuffer_Wrap(data->payloadArray, 128, 0, 128); + + data->lifetime = 900; + data->hoplimit = 77; + + data->interest = ccnxInterest_CreateWithImpl(data->interestImpl, + data->name, + data->lifetime, + data->keyid, + data->contentObjectHash, + data->hoplimit); + + ccnxInterest_SetPayload(data->interest, data->payload); + + longBowTestCase_SetClipBoardData(testCase, data); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxName_Release(&data->name); + parcBuffer_Release(&data->keyid); + parcBuffer_Release(&data->contentObjectHash); + parcBuffer_Release(&data->payload); + ccnxTlvDictionary_Release(&data->interest); + + parcMemory_Deallocate((void **) &data); + + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_TEARDOWN_FAILED; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxInterestReturnV1_Create) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxInterestReturn *interestReturn = + ccnxInterestReturn_Create(data->interest, CCNxInterestReturn_ReturnCode_NoRoute); + + ccnxInterestReturn_AssertValid(interestReturn); + + //assertTrue(ccnxInterestReturn_IsValid(interestReturn), "InterestReturn is not valid"); + ccnxTlvDictionary_Release(&interestReturn); +} + + +LONGBOW_TEST_CASE(Global, ccnxInterestReturnV1_AcquireRelease) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxInterestReturn *interestReturn = + ccnxInterestReturn_Create(data->interest, CCNxInterestReturn_ReturnCode_NoRoute); + + assertNotNull(interestReturn, "Expect non-NULL interestReturn"); + + CCNxInterestReturn *testInterestReturn = ccnxInterestReturn_Acquire(interestReturn); + assertNotNull(testInterestReturn, "Expected a non-NULL testInterestReturn"); + + ccnxInterestReturn_Release(&testInterestReturn); + assertNull(testInterestReturn, "Expected a NULL testInterestReturn"); + + ccnxInterestReturn_Release(&interestReturn); + assertNull(interestReturn, "Expected a NULL testInterestReturn"); +} + +LONGBOW_TEST_CASE(Global, ccnxInterestReturnV1_Equals) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxInterestReturn *interestReturn = + ccnxInterestReturn_Create(data->interest, CCNxInterestReturn_ReturnCode_NoRoute); + assertTrue(ccnxInterestReturn_Equals(interestReturn, interestReturn), "Expect same interestReturn pointers to be equal"); + + CCNxInterestReturn *acquiredIR = ccnxInterestReturn_Acquire(interestReturn); + assertTrue(ccnxInterestReturn_Equals(interestReturn, acquiredIR), "Expect acquired interestReturn to be equal to original"); + ccnxInterestReturn_Release(&acquiredIR); + + CCNxInterestReturn *identicalIR = + ccnxInterestReturn_Create(data->interest, CCNxInterestReturn_ReturnCode_NoRoute); + assertTrue(ccnxInterestReturn_Equals(interestReturn, identicalIR), "Expect identical interestReturn to be equal to original"); + + ccnxInterestReturn_Release(&identicalIR); + ccnxInterestReturn_Release(&interestReturn); +} + +LONGBOW_TEST_CASE(Global, ccnxInterestReturnV1_NotEquals) +{ + assertFalse(ccnxInterestReturn_Equals(NULL, NULL), "Expect two NULL interests to not be equal"); + + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxInterestReturn *interestReturn = + ccnxInterestReturn_Create(data->interest, CCNxInterestReturn_ReturnCode_NoRoute); + assertFalse(ccnxInterestReturn_Equals(interestReturn, NULL), "Expect a NULL interest to not be equal"); + + CCNxInterestReturn *testIR = + ccnxInterestReturn_Create(data->interest, CCNxInterestReturn_ReturnCode_MTUTooLarge); + assertFalse(ccnxInterestReturn_Equals(interestReturn, testIR), "Expect interestReturn's with different return codes to be !="); + + ccnxInterestReturn_Release(&testIR); + ccnxInterestReturn_Release(&interestReturn); +} + +LONGBOW_TEST_CASE(Global, ccnxInterestReturnV1_ToString) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxInterestReturn *interestReturn = + ccnxInterestReturn_Create(data->interest, CCNxInterestReturn_ReturnCode_NoRoute); + + const char *string = ccnxInterestReturn_ToString(interestReturn); + assertNotNull(string, "Expected non-null result from ccnxInterestReturn_ToString."); + + parcMemory_Deallocate((void **) &string); + + ccnxInterestReturn_Release(&interestReturn); +} + +LONGBOW_TEST_CASE(Global, ccnxInterestReturnV1_GetReturnCode) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxInterestReturn *interestReturn = + ccnxInterestReturn_Create(data->interest, CCNxInterestReturn_ReturnCode_NoRoute); + + CCNxInterestReturn_ReturnCode code = + ccnxInterestReturn_GetReturnCode(interestReturn); + + assertTrue((CCNxInterestReturn_ReturnCode_NoRoute == code), "InterestReturn wrong Return Code"); + ccnxInterestReturn_Release(&interestReturn); +} + +LONGBOW_TEST_CASE(Global, ccnxInterestReturnV1_GetInterestFields) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxInterestReturn *interestReturn = + ccnxInterestReturn_Create(data->interest, CCNxInterestReturn_ReturnCode_NoRoute); + + CCNxName *name = ccnxInterest_GetName(interestReturn); + assertTrue(ccnxName_Equals(name, data->name), "Names do not match") + { + printf("\ngot : \n"); ccnxName_Display(name, 3); + printf("\nexpected: \n"); ccnxName_Display(data->name, 3); + } + + uint32_t hopLimit = ccnxInterest_GetHopLimit(interestReturn); + assertTrue(hopLimit == data->hoplimit, "Wrong hoplimit: got %u expected %u", hopLimit, data->hoplimit); + + uint32_t lifetime = (uint32_t) ccnxInterest_GetLifetime(interestReturn); + assertTrue(lifetime == data->lifetime, "Wrong lifetime: got %u expected %u", lifetime, data->lifetime); + + PARCBuffer *buff = ccnxInterest_GetKeyIdRestriction(interestReturn); + assertTrue(parcBuffer_Equals(buff, data->keyid), "KeyIDs do not match") + { + printf("\ngot : \n"); parcBuffer_Display(buff, 3); + printf("\nexpected: \n"); parcBuffer_Display(data->keyid, 3); + } + + buff = ccnxInterest_GetPayload(interestReturn); + assertTrue(parcBuffer_Equals(buff, data->payload), "Payloads do not match") + { + printf("\ngot : \n"); parcBuffer_Display(buff, 3); + printf("\nexpected: \n"); parcBuffer_Display(data->payload, 3); + } + + ccnxInterestReturn_Release(&interestReturn); +} + + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_InterestReturnV1); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/test/test_ccnx_Key.c b/libccnx-common/ccnx/common/test/test_ccnx_Key.c new file mode 100755 index 00000000..c1bd5ed2 --- /dev/null +++ b/libccnx-common/ccnx/common/test/test_ccnx_Key.c @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ +#include <config.h> +#include "../ccnx_Key.c" +#include <LongBow/unit-test.h> + +#include <parc/algol/parc_SafeMemory.h> + +LONGBOW_TEST_RUNNER(ccnx_Key) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +LONGBOW_TEST_RUNNER_SETUP(ccnx_Key) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_Key) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxKey_CreateRelease); + LONGBOW_RUN_TEST_CASE(Global, ccnxKey_CreateFromHexString); + LONGBOW_RUN_TEST_CASE(Global, ccnxKey_FromByteBuffer); + LONGBOW_RUN_TEST_CASE(Global, ccnxKey_ToString); +} + +typedef struct { + char *hexString; +} TestData; + +static TestData* +commonSetup() +{ + char *hexString = "30819F300D06092A864886F70D010101050003818D0030818902818100A826C09E01FF4970428213C96312B46050514FD5F87E670A4784C75D8B23CD073B1CBEF328E538584E442A769DF77299192BCF3603F50F14C5664994250E5C24DF47B86EA5C7CA99B3584E9A63BC5993569FF3612C71AD46A088CDC7346B9BE021D4CA1764CF5434F993E6120363C551E2979BDB3F0345B4994BCED9CB260EEB0203010001"; + + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + data->hexString = parcMemory_StringDuplicate(hexString, strlen(hexString)); + return data; +} + +static void +commonTearDown(TestData *data) +{ + parcMemory_Deallocate((void **) &(data->hexString)); + parcMemory_Deallocate((void **) &data); +} + + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + TestData *data = commonSetup(); + longBowTestCase_SetClipBoardData(testCase, data); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + commonTearDown(data); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + + +LONGBOW_TEST_CASE(Global, ccnxKey_FromByteBuffer) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCBuffer *hexBuf = parcBuffer_ParseHexString(data->hexString); + CCNxKey *key = ccnxKey_Create(hexBuf); + parcBuffer_Release(&hexBuf); + ccnxKey_Release(&key); +} + +LONGBOW_TEST_CASE(Global, ccnxKey_CreateRelease) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxKey *key = ccnxKey_CreateFromHexString(data->hexString); + ccnxKey_AssertValid(key); + + char *string = ccnxKey_ToString(key); + + ccnxKey_Release(&key); + assertNull(key, "Key was not nulled out after Release()"); + + parcMemory_Deallocate((void **) &string); +} + +LONGBOW_TEST_CASE(Global, ccnxKey_CreateFromHexString) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxKey *key = ccnxKey_CreateFromHexString(data->hexString); + ccnxKey_AssertValid(key); + + char *string = ccnxKey_ToHexString(key); + + assertTrue(strcasecmp(data->hexString, string) == 0, + "Expected '%s' actual '%s'", data->hexString, string); + + ccnxKey_Release(&key); + assertNull(key, "Key was not nulled out after Release()"); + + parcMemory_Deallocate((void **) &string); +} + +LONGBOW_TEST_CASE(Global, ccnxKey_ToString) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxKey *key = ccnxKey_CreateFromHexString(data->hexString); + ccnxKey_AssertValid(key); + + char *string = ccnxKey_ToString(key); + + ccnxKey_Release(&key); + assertNull(key, "Key was not nulled out after Release()"); + + parcMemory_Deallocate((void **) &string); +} + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_Key); + exit(longBowMain(argc, argv, testRunner, NULL)); +} diff --git a/libccnx-common/ccnx/common/test/test_ccnx_KeyLocator.c b/libccnx-common/ccnx/common/test/test_ccnx_KeyLocator.c new file mode 100755 index 00000000..3e877179 --- /dev/null +++ b/libccnx-common/ccnx/common/test/test_ccnx_KeyLocator.c @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnx_KeyLocator.c" + +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +#include <parc/algol/parc_SafeMemory.h> + +LONGBOW_TEST_RUNNER(ccnx_KeyLocator) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnx_KeyLocator) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_KeyLocator) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxKeyLocator_Copy); + LONGBOW_RUN_TEST_CASE(Global, ccnxKeyLocator_Destroy); + LONGBOW_RUN_TEST_CASE(Global, ccnxKeyLocator_Equals); + LONGBOW_RUN_TEST_CASE(Global, ccnxKeyLocator_FromKey); + LONGBOW_RUN_TEST_CASE(Global, ccnxKeyLocator_FromKeyLink); + LONGBOW_RUN_TEST_CASE(Global, ccnxKeyLocator_GetKey); + LONGBOW_RUN_TEST_CASE(Global, ccnxKeyLocator_GetKeyName); + LONGBOW_RUN_TEST_CASE(Global, ccnxKeyLocator_GetType); + LONGBOW_RUN_TEST_CASE(Global, ccnxKeyLocator_IsKey); + LONGBOW_RUN_TEST_CASE(Global, ccnxKeyLocator_IsKeyName); + LONGBOW_RUN_TEST_CASE(Global, ccnxKeyLocator_ToString); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxKeyLocator_Copy) +{ + CCNxName *keyURIName = ccnxName_CreateFromCString("lci://name"); + CCNxLink *keyLink = ccnxLink_Create(keyURIName, NULL, NULL); + CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKeyLink(keyLink); + + ccnxKeyLocator_AssertValid(keyLocator); + + CCNxKeyLocator *copy = ccnxKeyLocator_Copy(keyLocator); + assertTrue(ccnxKeyLocator_Equals(copy, keyLocator), "Expected orig and copy to be the same"); + + ccnxKeyLocator_Release(&keyLocator); + ccnxKeyLocator_Release(©); + + ccnxName_Release(&keyURIName); + ccnxLink_Release(&keyLink); + + // Try FromHexString, too, for yucks. + PARCBuffer *keyBuffer = parcBuffer_WrapCString("hello world"); + PARCKeyId *keyId = parcKeyId_Create(keyBuffer); + PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyId, PARCSigningAlgorithm_RSA, keyBuffer); + parcKeyId_Release(&keyId); + parcBuffer_Release(&keyBuffer); + CCNxKeyLocator *keyLocator2 = ccnxKeyLocator_CreateFromKey(key); + + CCNxKeyLocator *copy2 = ccnxKeyLocator_Copy(keyLocator2); + assertTrue(ccnxKeyLocator_Equals(copy, keyLocator), "Expected orig and copy to be the same"); + + parcKey_Release(&key); + ccnxKeyLocator_Release(&keyLocator2); + ccnxKeyLocator_Release(©2); +} + +LONGBOW_TEST_CASE(Global, ccnxKeyLocator_Destroy) +{ + CCNxName *keyURIName = ccnxName_CreateFromCString("lci://name"); + CCNxLink *keyLink = ccnxLink_Create(keyURIName, NULL, NULL); + CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKeyLink(keyLink); + + ccnxKeyLocator_AssertValid(keyLocator); + + ccnxKeyLocator_Release(&keyLocator); + assertNull(keyLocator, "keyLocator was not nulled out by Release()"); + + ccnxLink_Release(&keyLink); + ccnxName_Release(&keyURIName); +} + +LONGBOW_TEST_CASE(Global, ccnxKeyLocator_Equals) +{ + char *hexString = "ABCDEF1234"; + PARCBuffer *keyBuffer = parcBuffer_WrapCString(hexString); + PARCKeyId *keyId = parcKeyId_Create(keyBuffer); + PARCKey *key1 = parcKey_CreateFromDerEncodedPublicKey(keyId, PARCSigningAlgorithm_RSA, keyBuffer); + CCNxKeyLocator *keyLocator1 = ccnxKeyLocator_CreateFromKey(key1); + parcKeyId_Release(&keyId); + parcBuffer_Release(&keyBuffer); + + CCNxKeyLocator *keyLocator1Copy = ccnxKeyLocator_Copy(keyLocator1); + + PARCBuffer *keyBuffer2 = parcBuffer_WrapCString(hexString); + PARCKeyId *keyId2 = parcKeyId_Create(keyBuffer2); + PARCKey *key2 = parcKey_CreateFromDerEncodedPublicKey(keyId2, PARCSigningAlgorithm_RSA, keyBuffer2); + CCNxKeyLocator *keyLocator2 = ccnxKeyLocator_CreateFromKey(key2); + parcBuffer_Release(&keyBuffer2); + parcKeyId_Release(&keyId2); + + CCNxName *keyURIName = ccnxName_CreateFromCString("lci://name"); + CCNxLink *keyLink = ccnxLink_Create(keyURIName, NULL, NULL); + CCNxKeyLocator *keyLocatorDiff = ccnxKeyLocator_CreateFromKeyLink(keyLink); + + ccnxKeyLocator_AssertValid(keyLocator1); + ccnxKeyLocator_AssertValid(keyLocator1Copy); + ccnxKeyLocator_AssertValid(keyLocator2); + ccnxKeyLocator_AssertValid(keyLocatorDiff); + + assertEqualsContract(ccnxKeyLocator_Equals, keyLocator1, keyLocator1Copy, keyLocator2, keyLocatorDiff); + + parcKey_Release(&key1); + ccnxKeyLocator_Release(&keyLocator1); + ccnxKeyLocator_Release(&keyLocator1Copy); + + parcKey_Release(&key2); + ccnxKeyLocator_Release(&keyLocator2); + + ccnxName_Release(&keyURIName); + ccnxLink_Release(&keyLink); + ccnxKeyLocator_Release(&keyLocatorDiff); +} + +LONGBOW_TEST_CASE(Global, ccnxKeyLocator_FromKey) +{ + char *hexString = "ABCDEF1234"; + PARCBuffer *keyBuffer = parcBuffer_WrapCString(hexString); + PARCKeyId *keyId = parcKeyId_Create(keyBuffer); + + PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyId, PARCSigningAlgorithm_RSA, keyBuffer); + CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKey(key); + parcKeyId_Release(&keyId); + parcBuffer_Release(&keyBuffer); + + ccnxKeyLocator_AssertValid(keyLocator); + + ccnxKeyLocator_Release(&keyLocator); + parcKey_Release(&key); +} + +LONGBOW_TEST_CASE(Global, ccnxKeyLocator_FromKeyLink) +{ + CCNxName *keyURIName = ccnxName_CreateFromCString("lci://name"); + CCNxLink *keyLink = ccnxLink_Create(keyURIName, NULL, NULL); + CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKeyLink(keyLink); + + ccnxKeyLocator_AssertValid(keyLocator); + + ccnxKeyLocator_Release(&keyLocator); + ccnxName_Release(&keyURIName); + ccnxLink_Release(&keyLink); +} + +LONGBOW_TEST_CASE(Global, ccnxKeyLocator_GetKey) +{ + char *hexString = "ABCDEF1234"; + PARCBuffer *keyBuffer = parcBuffer_WrapCString(hexString); + PARCKeyId *keyId = parcKeyId_Create(keyBuffer); + + PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyId, PARCSigningAlgorithm_RSA, keyBuffer); + CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKey(key); + + parcKeyId_Release(&keyId); + parcBuffer_Release(&keyBuffer); + + ccnxKeyLocator_AssertValid(keyLocator); + PARCKey *actual = ccnxKeyLocator_GetKey(keyLocator); + assertTrue(actual == key, "Actual certificate didn't match expected"); + + ccnxKeyLocator_Release(&keyLocator); + parcKey_Release(&key); +} + +LONGBOW_TEST_CASE(Global, ccnxKeyLocator_GetKeyName) +{ + CCNxName *keyURIName = ccnxName_CreateFromCString("lci://name/test"); + CCNxLink *keyLink = ccnxLink_Create(keyURIName, NULL, NULL); + CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKeyLink(keyLink); + + ccnxKeyLocator_AssertValid(keyLocator); + const CCNxName *actual = ccnxLink_GetName(ccnxKeyLocator_GetKeyLink(keyLocator)); + assertTrue(ccnxName_Equals(actual, keyURIName), "Actual keyName did not match the one returned by GetKeyName()"); + + ccnxKeyLocator_Release(&keyLocator); + ccnxName_Release(&keyURIName); + ccnxLink_Release(&keyLink); +} + +LONGBOW_TEST_CASE(Global, ccnxKeyLocator_GetType) +{ + // Try FromKey + char *hexString = "ABCDEF1234"; + PARCBuffer *keyBuffer = parcBuffer_WrapCString(hexString); + PARCKeyId *keyId = parcKeyId_Create(keyBuffer); + + PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyId, PARCSigningAlgorithm_RSA, keyBuffer); + CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKey(key); + parcKeyId_Release(&keyId); + parcBuffer_Release(&keyBuffer); + + ccnxKeyLocator_AssertValid(keyLocator); + assertTrue(ccnxKeyLocator_GetType(keyLocator) == CCNxKeyLocatorType_Key, "Actual certificate type didn't match expected type"); + + ccnxKeyLocator_Release(&keyLocator); + parcKey_Release(&key); + + // Try KeyName + CCNxName *keyURIName = ccnxName_CreateFromCString("lci://name/test"); + CCNxLink *keyLink = ccnxLink_Create(keyURIName, NULL, NULL); + keyLocator = ccnxKeyLocator_CreateFromKeyLink(keyLink); + + ccnxKeyLocator_AssertValid(keyLocator); + assertTrue(ccnxKeyLocator_GetType(keyLocator) == CCNxKeyLocatorType_Link, "Actual certificate type didn't match expected type"); + assertFalse(ccnxKeyLocator_GetType(keyLocator) == CCNxKeyLocatorType_Key, "Actual certificate type didn't match expected type"); + + ccnxKeyLocator_Release(&keyLocator); + ccnxName_Release(&keyURIName); + ccnxLink_Release(&keyLink); +} + +LONGBOW_TEST_CASE(Global, ccnxKeyLocator_IsKey) +{ + char *hexString = "ABCDEF1234"; + PARCBuffer *keyBuffer = parcBuffer_WrapCString(hexString); + PARCKeyId *keyId = parcKeyId_Create(keyBuffer); + + PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyId, PARCSigningAlgorithm_RSA, keyBuffer); + CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKey(key); + parcKeyId_Release(&keyId); + parcBuffer_Release(&keyBuffer); + + ccnxKeyLocator_AssertValid(keyLocator); + assertTrue(ccnxKeyLocator_IsKey(keyLocator), "Expected Iskey to be true"); + assertFalse(ccnxKeyLocator_IsKeyLink(keyLocator), "Expected IsKeyLink to be false"); + + ccnxKeyLocator_Release(&keyLocator); + parcKey_Release(&key); +} + +LONGBOW_TEST_CASE(Global, ccnxKeyLocator_IsKeyName) +{ + CCNxName *keyURIName = ccnxName_CreateFromCString("lci://name/test"); + CCNxLink *keyLink = ccnxLink_Create(keyURIName, NULL, NULL); + CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKeyLink(keyLink); + + ccnxKeyLocator_AssertValid(keyLocator); + assertFalse(ccnxKeyLocator_IsKey(keyLocator), "Expected Iskey to be false"); + assertTrue(ccnxKeyLocator_IsKeyLink(keyLocator), "Expected IsKeyLink to be true"); + + ccnxKeyLocator_Release(&keyLocator); + ccnxName_Release(&keyURIName); + ccnxLink_Release(&keyLink); +} + +LONGBOW_TEST_CASE(Global, ccnxKeyLocator_ToString) +{ + CCNxName *keyURIName = ccnxName_CreateFromCString("lci://name/test"); + CCNxLink *keyLink = ccnxLink_Create(keyURIName, NULL, NULL); + CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKeyLink(keyLink); + + ccnxKeyLocator_AssertValid(keyLocator); + + char *actualString = ccnxKeyLocator_ToString(keyLocator); + + assertTrue(0 == strncmp("KeyLocator", actualString, strlen("KeyLocator")), "ToString() did not return the expected prefix"); + + parcMemory_Deallocate((void **) &actualString); + + ccnxLink_Release(&keyLink); + ccnxName_Release(&keyURIName); + ccnxKeyLocator_Release(&keyLocator); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, ccnxKeyLocator_Create); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, ccnxKeyLocator_Create) +{ + CCNxName *keyURIName = ccnxName_CreateFromCString("lci://name"); + CCNxLink *keyLink = ccnxLink_Create(keyURIName, NULL, NULL); + CCNxKeyLocator *keyLocator = ccnxKeyLocator_CreateFromKeyLink(keyLink); + + ccnxKeyLocator_AssertValid(keyLocator); + + ccnxKeyLocator_Release(&keyLocator); + ccnxName_Release(&keyURIName); + ccnxLink_Release(&keyLink); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_KeyLocator); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/test/test_ccnx_KeystoreUtilities.c b/libccnx-common/ccnx/common/test/test_ccnx_KeystoreUtilities.c new file mode 100644 index 00000000..0ab770a5 --- /dev/null +++ b/libccnx-common/ccnx/common/test/test_ccnx_KeystoreUtilities.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnx_KeystoreUtilities.c" + +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> +#include <parc/security/parc_Security.h> + +#include <errno.h> +#include <ftw.h> + +typedef struct test_data { + char dirname[1024]; +} TestData; + +static int +deleteEntry(const char *fpath, const struct stat *sb, + int tflag, struct FTW *ftwbuf) +{ + if (tflag == FTW_DP) { + // directory in post-order + rmdir(fpath); + } else { + unlink(fpath); + } + return 0; /* To tell nftw() to continue */ +} + +__attribute__((unused)) +static void +recursiveDelete(const char *path) +{ + // only allow under tmp + assertTrue(strncmp(path, "/tmp/", 5) == 0, "Path must begin with /tmp/: %s", path); + // dont allow ".." + assertNull(strstr(path, ".."), "Path cannot have .. in it: %s", path); + + // depth first, dont't follow symlinks + int flags = FTW_DEPTH | FTW_PHYS; + + // maximum 20 fds open at a time + int max_fd = 20; + + int failure = nftw(path, deleteEntry, max_fd, flags); + assertFalse(failure, "Error on recursive delete: (%d) %s", errno, strerror(errno)); +} + +static TestData * +commonSetup(const char *testCaseName) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + sprintf(data->dirname, "/tmp/%s.%d", testCaseName, getpid()); + mkdir(data->dirname, S_IRWXU | S_IRWXG); + setenv("HOME", data->dirname, 1); + + return data; +} + +static void +commonTeardown(TestData **dataPtr) +{ + TestData *data = *dataPtr; + + recursiveDelete(data->dirname); + parcMemory_Deallocate((void **) &data); + *dataPtr = NULL; +} + +LONGBOW_TEST_RUNNER(ccnx_KeystoreUtilities) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnx_KeystoreUtilities) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_KeystoreUtilities) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + TestData *data = commonSetup(longBowTestCase_GetName(testCase)); + longBowTestCase_SetClipBoardData(testCase, data); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + commonTeardown(&data); + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, ccnxKeystoreUtilities_ConstructPath); + LONGBOW_RUN_TEST_CASE(Local, ccnxKeystoreUtilities_HomeDirectoryFromEnv); + LONGBOW_RUN_TEST_CASE(Local, ccnxKeystoreUtilities_HomeDirectoryFromPasswd); + + LONGBOW_RUN_TEST_CASE(Local, ccnxKeystoreUtilities_OpenFromHomeDirectory_Missing); + + LONGBOW_RUN_TEST_CASE(Local, ccnxKeystoreUtilities_OpenFromHomeDirectory_Newfile); + LONGBOW_RUN_TEST_CASE(Local, ccnxKeystoreUtilities_OpenFromHomeDirectory_Oldfile); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + parcSecurity_Init(); + + TestData *data = commonSetup(longBowTestCase_GetName(testCase)); + longBowTestCase_SetClipBoardData(testCase, data); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + commonTeardown(&data); + + parcSecurity_Fini(); + + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, ccnxKeystoreUtilities_ConstructPath) +{ + const char *dir = "/some/where"; + const char *file = "else"; + const char *truth = "/some/where/else"; + + char *test = ccnxKeystoreUtilities_ConstructPath(dir, file); + assertTrue(strcmp(truth, test) == 0, "Wrong path, expected %s got %s", truth, test); + parcMemory_Deallocate((void **) &test); +} + +LONGBOW_TEST_CASE(Local, ccnxKeystoreUtilities_HomeDirectoryFromEnv) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + char *dir = ccnxKeystoreUtilities_HomeDirectoryFromEnv(); + assertNotNull(dir, "Did not get HOME variable from environment"); + assertTrue(strcmp(dir, data->dirname) == 0, "HOME directory not correct, expecting %s got %s\n", data->dirname, dir); + parcMemory_Deallocate((void **) &dir); +} + +LONGBOW_TEST_CASE(Local, ccnxKeystoreUtilities_HomeDirectoryFromPasswd) +{ + char *dir = ccnxKeystoreUtilities_HomeDirectoryFromPasswd(); + assertNotNull(dir, "Did not get HOME variable from environment"); + parcMemory_Deallocate((void **) &dir); +} + +/** + * Create a temporary directory, set HOME to it, then try to open, but do + * not create the keystore. should return NULL. + */ +LONGBOW_TEST_CASE(Local, ccnxKeystoreUtilities_OpenFromHomeDirectory_Missing) +{ + KeystoreParams *params = ccnxKeystoreUtilities_OpenFromHomeDirectory("abcd"); + assertNull(params, "Signer should have been null opening from non-existent keystore"); +} + + +/** + * Create a keystore with the old default name in the old location + */ +LONGBOW_TEST_CASE(Local, ccnxKeystoreUtilities_OpenFromHomeDirectory_Oldfile) +{ + char *homedir = ccnxKeystoreUtilities_GetHomeDirectory(); + char *ccnxdir = ccnxKeystoreUtilities_ConstructPath(homedir, ".ccnx"); + mkdir(ccnxdir, 0700); + char *path = ccnxKeystoreUtilities_ConstructPath(ccnxdir, ".ccnx_keystore"); + + bool success = parcPkcs12KeyStore_CreateFile(path, "1234", "ccnxuser", 1024, 365); + assertTrue(success, "parcPkcs12KeyStore_CreateFile() failed."); + + KeystoreParams *signer = ccnxKeystoreUtilities_OpenFromHomeDirectory("1234"); + assertNotNull(signer, "Signer should be non-null opening from a file we just created"); + keystoreParams_Destroy(&signer); + + parcMemory_Deallocate((void **) &path); + parcMemory_Deallocate((void **) &ccnxdir); + parcMemory_Deallocate((void **) &homedir); +} + +/** + * Create a keystore with the new default name in the old location + */ +LONGBOW_TEST_CASE(Local, ccnxKeystoreUtilities_OpenFromHomeDirectory_Newfile) +{ + char *homedir = ccnxKeystoreUtilities_GetHomeDirectory(); + char *ccnxdir = ccnxKeystoreUtilities_ConstructPath(homedir, ".ccnx"); + mkdir(ccnxdir, 0700); + char *path = ccnxKeystoreUtilities_ConstructPath(ccnxdir, ".ccnx_keystore.p12"); + + bool success = parcPkcs12KeyStore_CreateFile(path, "1234", "ccnxuser", 1024, 365); + assertTrue(success, "parcPkcs12KeyStore_CreateFile() failed."); + + KeystoreParams *signer = ccnxKeystoreUtilities_OpenFromHomeDirectory("1234"); + assertNotNull(signer, "Signer should be non-null opening from a file we just created"); + keystoreParams_Destroy(&signer); + + parcMemory_Deallocate((void **) &path); + parcMemory_Deallocate((void **) &ccnxdir); + parcMemory_Deallocate((void **) &homedir); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_KeystoreUtilities); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/test/test_ccnx_Link.c b/libccnx-common/ccnx/common/test/test_ccnx_Link.c new file mode 100755 index 00000000..87105468 --- /dev/null +++ b/libccnx-common/ccnx/common/test/test_ccnx_Link.c @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. + +#include <ccnx/common/ccnx_Link.c> + +#include <LongBow/unit-test.h> + +#include <parc/algol/parc_Object.h> +#include <parc/algol/parc_SafeMemory.h> +#include <parc/algol/parc_ArrayList.h> +#include <parc/testing/parc_ObjectTesting.h> + +LONGBOW_TEST_RUNNER(ccnx_Link) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnx_Link) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_Link) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxLink_Create_Full); + LONGBOW_RUN_TEST_CASE(Global, ccnxLink_Create_EmptyKeyID); + LONGBOW_RUN_TEST_CASE(Global, ccnxLink_Create_EmptyContentObjectHash); + LONGBOW_RUN_TEST_CASE(Global, ccnxLink_Create_EmptyBoth); + LONGBOW_RUN_TEST_CASE(Global, ccnxLink_AcquireRelease); + + LONGBOW_RUN_TEST_CASE(Global, ccnxLink_GetName); + LONGBOW_RUN_TEST_CASE(Global, ccnxLink_GetKeyID); + LONGBOW_RUN_TEST_CASE(Global, ccnxLink_GetContentObjectHash); + + LONGBOW_RUN_TEST_CASE(Global, ccnxLink_Create_ToString); + + LONGBOW_RUN_TEST_CASE(Global, ccnxLink_Equals); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxLink_Create_Full) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar/name"); + PARCBuffer *keyId = parcBuffer_Allocate(10); + PARCBuffer *contentObjectHash = parcBuffer_Allocate(10); + + CCNxLink *object = ccnxLink_Create(name, keyId, contentObjectHash); + + assertNotNull(object, "Expected non-null return value."); + + ccnxLink_Release(&object); + + ccnxName_Release(&name); + parcBuffer_Release(&keyId); + parcBuffer_Release(&contentObjectHash); +} + +LONGBOW_TEST_CASE(Global, ccnxLink_Create_EmptyKeyID) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar/name"); + PARCBuffer *keyId = NULL; + PARCBuffer *contentObjectHash = parcBuffer_Allocate(10); + + CCNxLink *object = ccnxLink_Create(name, keyId, contentObjectHash); + + assertNotNull(object, "Expected non-null return value."); + + ccnxLink_Release(&object); + + ccnxName_Release(&name); + parcBuffer_Release(&contentObjectHash); +} + +LONGBOW_TEST_CASE(Global, ccnxLink_Create_EmptyContentObjectHash) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar/name"); + PARCBuffer *keyId = parcBuffer_Allocate(10); + PARCBuffer *contentObjectHash = NULL; + + CCNxLink *object = ccnxLink_Create(name, keyId, contentObjectHash); + + assertNotNull(object, "Expected non-null return value."); + + ccnxLink_Release(&object); + + ccnxName_Release(&name); + parcBuffer_Release(&keyId); +} + +LONGBOW_TEST_CASE(Global, ccnxLink_Create_EmptyBoth) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar/name"); + PARCBuffer *keyId = NULL; + PARCBuffer *contentObjectHash = NULL; + + CCNxLink *object = ccnxLink_Create(name, keyId, contentObjectHash); + + assertNotNull(object, "Expected non-null return value."); + + ccnxLink_Release(&object); + + ccnxName_Release(&name); +} + +LONGBOW_TEST_CASE(Global, ccnxLink_AcquireRelease) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar/name"); + PARCBuffer *keyId = parcBuffer_Allocate(10); + PARCBuffer *contentObjectHash = parcBuffer_Allocate(10); + + CCNxLink *object = ccnxLink_Create(name, keyId, contentObjectHash); + parcObjectTesting_AssertAcquireReleaseContract(ccnxLink_Acquire, object); + + ccnxLink_Release(&object); + + ccnxName_Release(&name); + parcBuffer_Release(&keyId); + parcBuffer_Release(&contentObjectHash); +} + +LONGBOW_TEST_CASE(Global, ccnxLink_GetName) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar/name"); + PARCBuffer *keyId = parcBuffer_Allocate(10); + PARCBuffer *contentObjectHash = parcBuffer_Allocate(10); + + CCNxLink *object = ccnxLink_Create(name, keyId, contentObjectHash); + + const CCNxName *actualName = ccnxLink_GetName(object); + assertNotNull(actualName, "Expected non-null return value."); + assertTrue(ccnxName_Equals(name, actualName), "Expected the same name back"); + + ccnxLink_Release(&object); + + ccnxName_Release(&name); + parcBuffer_Release(&keyId); + parcBuffer_Release(&contentObjectHash); +} + +LONGBOW_TEST_CASE(Global, ccnxLink_GetKeyID) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar/name"); + PARCBuffer *keyId = parcBuffer_Allocate(10); + PARCBuffer *contentObjectHash = parcBuffer_Allocate(20); + + CCNxLink *object = ccnxLink_Create(name, keyId, contentObjectHash); + + PARCBuffer *buffer = ccnxLink_GetKeyID(object); + assertNotNull(buffer, "Expected non-null return value."); + assertTrue(parcBuffer_Capacity(buffer) == 10, "Expected the same buffer size back"); + + ccnxLink_Release(&object); + + ccnxName_Release(&name); + parcBuffer_Release(&keyId); + parcBuffer_Release(&contentObjectHash); +} + +LONGBOW_TEST_CASE(Global, ccnxLink_GetContentObjectHash) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar/name"); + PARCBuffer *keyId = parcBuffer_Allocate(10); + PARCBuffer *contentObjectHash = parcBuffer_Allocate(20); + + CCNxLink *object = ccnxLink_Create(name, keyId, contentObjectHash); + + PARCBuffer *buffer = ccnxLink_GetContentObjectHash(object); + assertNotNull(buffer, "Expected non-null return value."); + assertTrue(parcBuffer_Capacity(buffer) == 20, "Expected the same buffer size back"); + + ccnxLink_Release(&object); + + ccnxName_Release(&name); + parcBuffer_Release(&keyId); + parcBuffer_Release(&contentObjectHash); +} + +LONGBOW_TEST_CASE(Global, ccnxLink_Equals) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar/name"); + PARCBuffer *keyId = parcBuffer_Allocate(10); + PARCBuffer *contentObjectHash = parcBuffer_Allocate(20); + CCNxLink *x = ccnxLink_Create(name, keyId, contentObjectHash); + ccnxName_Release(&name); + parcBuffer_Release(&keyId); + parcBuffer_Release(&contentObjectHash); + + name = ccnxName_CreateFromCString("lci:/foo/bar/name"); + keyId = parcBuffer_Allocate(10); + contentObjectHash = parcBuffer_Allocate(20); + CCNxLink *y = ccnxLink_Create(name, keyId, contentObjectHash); + ccnxName_Release(&name); + parcBuffer_Release(&keyId); + parcBuffer_Release(&contentObjectHash); + + name = ccnxName_CreateFromCString("lci:/foo/bar/name"); + keyId = parcBuffer_Allocate(10); + contentObjectHash = parcBuffer_Allocate(20); + CCNxLink *z = ccnxLink_Create(name, keyId, contentObjectHash); + ccnxName_Release(&name); + parcBuffer_Release(&keyId); + parcBuffer_Release(&contentObjectHash); + + name = ccnxName_CreateFromCString("lci:/foo/bar/othername"); + keyId = parcBuffer_Allocate(10); + contentObjectHash = parcBuffer_Allocate(20); + CCNxLink *unequal1 = ccnxLink_Create(name, keyId, contentObjectHash); + ccnxName_Release(&name); + parcBuffer_Release(&keyId); + parcBuffer_Release(&contentObjectHash); + + name = ccnxName_CreateFromCString("lci:/foo/bar/name"); + keyId = NULL; + contentObjectHash = parcBuffer_Allocate(20); + CCNxLink *unequal2 = ccnxLink_Create(name, keyId, contentObjectHash); + ccnxName_Release(&name); + parcBuffer_Release(&contentObjectHash); + + name = ccnxName_CreateFromCString("lci:/foo/bar/name"); + keyId = parcBuffer_Allocate(10); + contentObjectHash = NULL; + CCNxLink *unequal3 = ccnxLink_Create(name, keyId, contentObjectHash); + ccnxName_Release(&name); + parcBuffer_Release(&keyId); + + assertEqualsContract(ccnxLink_Equals, x, y, z, unequal1, unequal2, unequal3); + + ccnxLink_Release(&x); + ccnxLink_Release(&y); + ccnxLink_Release(&z); + ccnxLink_Release(&unequal1); + ccnxLink_Release(&unequal2); + ccnxLink_Release(&unequal3); +} + +LONGBOW_TEST_CASE(Global, ccnxLink_Create_ToString) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar/name"); + PARCBuffer *keyId = parcBuffer_Allocate(10); + PARCBuffer *contentObjectHash = parcBuffer_Allocate(20); + CCNxLink *object = ccnxLink_Create(name, keyId, contentObjectHash); + + char *string = ccnxLink_ToString(object); + assertNotNull(string, "Expected non-null string."); + parcMemory_Deallocate((void **) &string); + + ccnxLink_Release(&object); + + ccnxName_Release(&name); + parcBuffer_Release(&keyId); + parcBuffer_Release(&contentObjectHash); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_Link); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/test/test_ccnx_Manifest.c b/libccnx-common/ccnx/common/test/test_ccnx_Manifest.c new file mode 100755 index 00000000..583c9a79 --- /dev/null +++ b/libccnx-common/ccnx/common/test/test_ccnx_Manifest.c @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnx_Manifest.c" + +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + +#include <parc/testing/parc_ObjectTesting.h> + +#include <ccnx/common/ccnx_Interest.h> + +typedef struct test_data { + CCNxManifest *object; + CCNxManifest *manifestWithNamelessGroup; + CCNxManifest *nameless; + PARCLinkedList *interestListFromGroupLocator; + PARCLinkedList *interestListFromManifestLocator; + PARCLinkedList *interestListFromOverrideLocator; + CCNxName *overrideLocator; +} ManifestTestData; + +static ManifestTestData * +_commonSetup(void) +{ + ManifestTestData *data = parcMemory_AllocateAndClear(sizeof(ManifestTestData)); + + data->overrideLocator = ccnxName_CreateFromCString("ccnx:/override"); + + CCNxName *name = ccnxName_CreateFromCString("ccnx:/my/manifest"); + CCNxManifest *manifest = ccnxManifest_Create(name); + CCNxManifest *nameless = ccnxManifest_CreateNameless(); + CCNxManifest *manifestWithNamelessGroup = ccnxManifest_Create(name); + + data->interestListFromGroupLocator = parcLinkedList_Create(); + data->interestListFromManifestLocator = parcLinkedList_Create(); + data->interestListFromOverrideLocator = parcLinkedList_Create(); + data->object = manifest; + data->nameless = nameless; + data->manifestWithNamelessGroup = manifestWithNamelessGroup; + + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + CCNxManifestHashGroup *namelessGroup = ccnxManifestHashGroup_Create(); + + CCNxName *locator = ccnxName_CreateFromCString("ccnx:/locator"); + ccnxManifestHashGroup_SetLocator(group, locator); + + // Create pointers for the pieces of data + PARCBuffer *digest1 = parcBuffer_Allocate(32); + PARCBuffer *digest2 = parcBuffer_Allocate(32); + ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, digest1); + ccnxManifestHashGroup_AppendPointer(namelessGroup, CCNxManifestHashGroupPointerType_Data, digest1); + ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Manifest, digest2); + ccnxManifestHashGroup_AppendPointer(namelessGroup, CCNxManifestHashGroupPointerType_Data, digest2); + + // Create the corresponding interests based on the three locator cases + // 1. The locator is inherited from the hash group + // 2. The locator is inherited from the manifest + // 3. The locator is overridden + CCNxInterest *interest1 = ccnxInterest_CreateSimple(locator); + ccnxInterest_SetContentObjectHashRestriction(interest1, digest1); + parcLinkedList_Append(data->interestListFromGroupLocator, interest1); + ccnxInterest_Release(&interest1); + + interest1 = ccnxInterest_CreateSimple(name); + ccnxInterest_SetContentObjectHashRestriction(interest1, digest1); + parcLinkedList_Append(data->interestListFromManifestLocator, interest1); + ccnxInterest_Release(&interest1); + + interest1 = ccnxInterest_CreateSimple(data->overrideLocator); + ccnxInterest_SetContentObjectHashRestriction(interest1, digest1); + parcLinkedList_Append(data->interestListFromOverrideLocator, interest1); + ccnxInterest_Release(&interest1); + + CCNxInterest *interest2 = ccnxInterest_CreateSimple(locator); + ccnxInterest_SetContentObjectHashRestriction(interest2, digest2); + parcLinkedList_Append(data->interestListFromGroupLocator, interest2); + ccnxInterest_Release(&interest2); + + interest2 = ccnxInterest_CreateSimple(name); + ccnxInterest_SetContentObjectHashRestriction(interest2, digest2); + parcLinkedList_Append(data->interestListFromManifestLocator, interest2); + ccnxInterest_Release(&interest2); + + interest2 = ccnxInterest_CreateSimple(data->overrideLocator); + ccnxInterest_SetContentObjectHashRestriction(interest2, digest2); + parcLinkedList_Append(data->interestListFromOverrideLocator, interest2); + ccnxInterest_Release(&interest2); + + ccnxName_Release(&name); + ccnxName_Release(&locator); + parcBuffer_Release(&digest1); + parcBuffer_Release(&digest2); + + ccnxManifest_AddHashGroup(manifest, group); + ccnxManifest_AddHashGroup(manifestWithNamelessGroup, namelessGroup); + ccnxManifest_AddHashGroup(nameless, namelessGroup); + + ccnxManifestHashGroup_Release(&group); + ccnxManifestHashGroup_Release(&namelessGroup); + + return data; +} + +static void +_commonTeardown(ManifestTestData *data) +{ + ccnxManifest_Release(&data->object); + ccnxManifest_Release(&data->nameless); + ccnxManifest_Release(&data->manifestWithNamelessGroup); + + parcLinkedList_Release(&data->interestListFromGroupLocator); + parcLinkedList_Release(&data->interestListFromManifestLocator); + parcLinkedList_Release(&data->interestListFromOverrideLocator); + + ccnxName_Release(&data->overrideLocator); + parcMemory_Deallocate((void **) &data); +} + +LONGBOW_TEST_RUNNER(ccnx_Manifest) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnx_Manifest) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_Manifest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxManifest_AcquireRelease); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifest_Create); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifest_AddHashGroup); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifest_GetHashGroup); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifest_GetNumberOfHashGroups); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifest_GetName); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifest_Equals); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifest_ToString); + + LONGBOW_RUN_TEST_CASE(Global, ccnxManifest_CreateInterestList_OverrideLocator); + // LONGBOW_RUN_TEST_CASE(Global, ccnxManifest_CreateInterestList_ManifestLocator); + // LONGBOW_RUN_TEST_CASE(Global, ccnxManifest_CreateInterestList_GroupLocator); + // LONGBOW_RUN_TEST_CASE(Global, ccnxManifest_CreateInterestList_NoLocator); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + longBowTestCase_SetClipBoardData(testCase, _commonSetup()); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + _commonTeardown(longBowTestCase_GetClipBoardData(testCase)); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxManifest_AcquireRelease) +{ + CCNxName *name = ccnxName_CreateFromCString("ccnx:/my/manifest"); + CCNxManifest *manifest = ccnxManifest_Create(name); + ccnxName_Release(&name); + + parcObjectTesting_AssertAcquireReleaseContract(ccnxManifest_Acquire, manifest); + + ccnxManifest_Release(&manifest); +} + +LONGBOW_TEST_CASE(Global, ccnxManifest_Create) +{ + CCNxName *name = ccnxName_CreateFromCString("ccnx:/my/manifest"); + CCNxManifest *manifest = ccnxManifest_Create(name); + + assertNotNull(manifest, "Expected the Manifest to be created without errors."); + const CCNxName *copy = ccnxManifest_GetName(manifest); + + assertTrue(ccnxName_Equals(name, copy), "Expected name to equal %s, got %s", ccnxName_ToString(name), ccnxName_ToString(copy)); + + ccnxName_Release(&name); + ccnxManifest_Release(&manifest); +} + +LONGBOW_TEST_CASE(Global, ccnxManifest_AddHashGroup) +{ + ManifestTestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxManifest *manifest = data->object; + + size_t numGroups = ccnxManifest_GetNumberOfHashGroups(manifest); + + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + ccnxManifest_AddHashGroup(manifest, group); + + size_t expected = numGroups + 1; + size_t actual = ccnxManifest_GetNumberOfHashGroups(manifest); + assertTrue(actual == expected, "Expected %zu, got %zu", expected, actual); + + ccnxManifestHashGroup_Release(&group); +} + +LONGBOW_TEST_CASE(Global, ccnxManifest_GetHashGroup) +{ + ManifestTestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxManifest *manifest = data->object; + + CCNxManifestHashGroup *group = ccnxManifest_GetHashGroupByIndex(manifest, 0); + CCNxName *expected = ccnxName_CreateFromCString("ccnx:/locator"); + const CCNxName *actual = ccnxManifestHashGroup_GetLocator(group); + assertTrue(ccnxName_Equals(expected, actual), "Expected %s, got %s", ccnxName_ToString(expected), ccnxName_ToString(actual)); + + ccnxName_Release(&expected); + ccnxManifestHashGroup_Release(&group); +} + +LONGBOW_TEST_CASE(Global, ccnxManifest_GetNumberOfHashGroups) +{ + ManifestTestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxManifest *manifest = data->object; + + size_t before = ccnxManifest_GetNumberOfHashGroups(manifest); + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + ccnxManifest_AddHashGroup(manifest, group); + + size_t actual = ccnxManifest_GetNumberOfHashGroups(manifest); + size_t expected = before + 1; + + assertTrue(expected == actual, "Expected %zu, got %zu", expected, actual); + + ccnxManifestHashGroup_Release(&group); +} + +LONGBOW_TEST_CASE(Global, ccnxManifest_CreateInterestList_NoLocator) +{ + ManifestTestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxManifest *nameless = data->nameless; + + PARCLinkedList *interestList = ccnxManifest_CreateInterestList(nameless, NULL); + assertTrue(parcLinkedList_Size(interestList) == 0, "Expected the interest list to be empty since there was no valid locator"); + parcLinkedList_Release(&interestList); +} + +LONGBOW_TEST_CASE(Global, ccnxManifest_CreateInterestList_GroupLocator) +{ + ManifestTestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxManifest *manifest = data->object; + + PARCLinkedList *interestList = ccnxManifest_CreateInterestList(manifest, NULL); + assertTrue(parcLinkedList_Equals(interestList, data->interestListFromGroupLocator), "Expected the interest lists to be equal"); + parcLinkedList_Release(&interestList); +} + +LONGBOW_TEST_CASE(Global, ccnxManifest_CreateInterestList_ManifestLocator) +{ + ManifestTestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxManifest *manifestWithNamelessGroup = data->manifestWithNamelessGroup; + + PARCLinkedList *interestList = ccnxManifest_CreateInterestList(manifestWithNamelessGroup, NULL); + assertTrue(parcLinkedList_Equals(interestList, data->interestListFromManifestLocator), "Expected the interest lists to be equal"); + parcLinkedList_Release(&interestList); +} + +LONGBOW_TEST_CASE(Global, ccnxManifest_CreateInterestList_OverrideLocator) +{ + ManifestTestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxManifest *nameless = data->nameless; + CCNxName *overrideLocator = data->overrideLocator; + + PARCLinkedList *interestList = ccnxManifest_CreateInterestList(nameless, overrideLocator); + assertTrue(parcLinkedList_Equals(interestList, data->interestListFromOverrideLocator), "Expected the interest lists to be equal"); + parcLinkedList_Release(&interestList); +} + +LONGBOW_TEST_CASE(Global, ccnxManifest_GetName) +{ + CCNxName *name = ccnxName_CreateFromCString("ccnx:/my/manifest"); + CCNxManifest *manifest = ccnxManifest_Create(name); + + assertNotNull(manifest, "Expected the Manifest to be created without errors."); + const CCNxName *copy = ccnxManifest_GetName(manifest); + + assertTrue(ccnxName_Equals(name, copy), "Expected name to equal %s, got %s", ccnxName_ToString(name), ccnxName_ToString(copy)); + + ccnxName_Release(&name); + ccnxManifest_Release(&manifest); +} + +LONGBOW_TEST_CASE(Global, ccnxManifest_Equals) +{ + CCNxName *name = ccnxName_CreateFromCString("ccnx:/my/manifest"); + CCNxManifest *x = ccnxManifest_Create(name); + CCNxManifest *y = ccnxManifest_Create(name); + CCNxManifest *z = ccnxManifest_Create(name); + + CCNxName *name1 = ccnxName_CreateFromCString("ccnx:/not/my/manifest"); + CCNxManifest *u1 = ccnxManifest_Create(name1); + + parcObjectTesting_AssertEqualsFunction(ccnxManifest_Equals, x, y, z, u1, NULL); + + ccnxName_Release(&name); + ccnxName_Release(&name1); + ccnxManifest_Release(&x); + ccnxManifest_Release(&y); + ccnxManifest_Release(&z); + ccnxManifest_Release(&u1); +} + +LONGBOW_TEST_CASE(Global, ccnxManifest_ToString) +{ + CCNxName *name = ccnxName_CreateFromCString("ccnx:/my/manifest"); + CCNxManifest *manifest = ccnxManifest_Create(name); + + assertNotNull(manifest, "Expected the Manifest to be created without errors."); + const CCNxName *copy = ccnxManifest_GetName(manifest); + + assertTrue(ccnxName_Equals(name, copy), "Expected name to equal %s, got %s", ccnxName_ToString(name), ccnxName_ToString(copy)); + + ccnxName_Release(&name); + ccnxManifest_Release(&manifest); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_Manifest); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/test/test_ccnx_ManifestHashGroup.c b/libccnx-common/ccnx/common/test/test_ccnx_ManifestHashGroup.c new file mode 100644 index 00000000..c09fa63d --- /dev/null +++ b/libccnx-common/ccnx/common/test/test_ccnx_ManifestHashGroup.c @@ -0,0 +1,515 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnx_ManifestHashGroup.c" + +#include <inttypes.h> +#include <ccnx/common/ccnx_Manifest.h> + +#include <ccnx/common/ccnx_Name.h> +#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.h> +#include <ccnx/common/codec/ccnxCodec_TlvPacket.h> +#include <ccnx/common/ccnx_WireFormatMessage.h> + +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> +#include <parc/algol/parc_Object.h> +#include <parc/algol/parc_ArrayList.h> + +#include <parc/testing/parc_ObjectTesting.h> + +LONGBOW_TEST_RUNNER(ccnx_ManifestHashGroup) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnx_ManifestHashGroup) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_ManifestHashGroup) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_AcquireRelease); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_Create); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_CreateFromJson); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_AppendGetPointer); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_PrependGetPointer); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_ToString); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_ToJson); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_IsFull); + + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_CreateInterestList_GroupLocator); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_CreateInterestList_OverrideLocator); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_CreateInterestList_NoLocator); + + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_Equals); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_Iterator); + + // Metadata + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_BlockSize); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_DataSize); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_EntrySize); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_TreeHeight); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_Locator); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_OverallDataDigest); + LONGBOW_RUN_TEST_CASE(Global, ccnxManifestHashGroup_HasMetadata); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_AcquireRelease) +{ + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + assertNotNull(group, "Expected non-null CCNxManifestHashGroup"); + + parcObjectTesting_AssertAcquireReleaseContract(ccnxManifestHashGroup_Acquire, group); + + ccnxManifestHashGroup_Release(&group); +} + +LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_Create) +{ + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + assertNotNull(group, "Expected non-null CCNxManifestHashGroup"); + ccnxManifestHashGroup_Release(&group); +} + +LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_CreateFromJson) +{ + char *jsonString = "{ \"HashGroup\" : [ { \"type\" : 0, \"digest\" : \"FFFF\" } ] }"; + PARCJSON *json = parcJSON_ParseString(jsonString); + + CCNxManifestHashGroup *group = ccnxManifestHashGroup_CreateFromJson(json); + assertNotNull(group, "Expected non-null CCNxManifestHashGroup"); + + size_t actual = ccnxManifestHashGroup_GetNumberOfPointers(group); + size_t expected = 1; + + assertTrue(actual == expected, "Expected %zu pointers, got %zu", expected, actual); + + parcJSON_Release(&json); + ccnxManifestHashGroup_Release(&group); +} + +LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_AppendGetPointer) +{ + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + assertNotNull(group, "Expected non-null CCNxManifestHashGroup"); + + PARCBuffer *buffer1 = parcBuffer_Allocate(32); + PARCBuffer *buffer2 = parcBuffer_Allocate(32); + + ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, buffer1); + ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Manifest, buffer2); + + size_t expected = 2; + size_t actual = ccnxManifestHashGroup_GetNumberOfPointers(group); + + assertTrue(expected == actual, "Expected %zu, got %zu", expected, actual); + assertTrue(ccnxManifestHashGroupPointer_GetType(ccnxManifestHashGroup_GetPointerAtIndex(group, 0)) == CCNxManifestHashGroupPointerType_Data, "Expected data in the first slot"); + assertTrue(ccnxManifestHashGroupPointer_GetType(ccnxManifestHashGroup_GetPointerAtIndex(group, 1)) == CCNxManifestHashGroupPointerType_Manifest, "Expected data in the first slot"); + + parcBuffer_Release(&buffer1); + parcBuffer_Release(&buffer2); + + ccnxManifestHashGroup_Release(&group); +} + +LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_PrependGetPointer) +{ + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + assertNotNull(group, "Expected non-null CCNxManifestHashGroup"); + + PARCBuffer *buffer1 = parcBuffer_Allocate(32); + PARCBuffer *buffer2 = parcBuffer_Allocate(32); + + ccnxManifestHashGroup_PrependPointer(group, CCNxManifestHashGroupPointerType_Data, buffer1); + ccnxManifestHashGroup_PrependPointer(group, CCNxManifestHashGroupPointerType_Manifest, buffer2); + + size_t expected = 2; + size_t actual = ccnxManifestHashGroup_GetNumberOfPointers(group); + + assertTrue(expected == actual, "Expected %zu, got %zu", expected, actual); + assertTrue(ccnxManifestHashGroupPointer_GetType(ccnxManifestHashGroup_GetPointerAtIndex(group, 1)) == CCNxManifestHashGroupPointerType_Data, "Expected data in the first slot"); + assertTrue(ccnxManifestHashGroupPointer_GetType(ccnxManifestHashGroup_GetPointerAtIndex(group, 0)) == CCNxManifestHashGroupPointerType_Manifest, "Expected data in the first slot"); + + parcBuffer_Release(&buffer1); + parcBuffer_Release(&buffer2); + + ccnxManifestHashGroup_Release(&group); +} + +static CCNxManifestHashGroup * +_createHashGroup(CCNxName *locator, size_t n, size_t blockSize, size_t dataSize, size_t entrySize, size_t treeHeight) +{ + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + + if (locator != NULL) { + ccnxManifestHashGroup_SetLocator(group, locator); + } + + for (size_t i = 0; i < n; i++) { + PARCBuffer *buffer = parcBuffer_Allocate(32); + ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, buffer); + parcBuffer_Release(&buffer); + } + + if (blockSize != 0) { + ccnxManifestHashGroup_SetBlockSize(group, blockSize); + } + + if (dataSize != 0) { + ccnxManifestHashGroup_SetDataSize(group, dataSize); + } + + if (entrySize != 0) { + ccnxManifestHashGroup_SetEntrySize(group, entrySize); + } + + if (treeHeight != 0) { + ccnxManifestHashGroup_SetTreeHeight(group, treeHeight); + } + + return group; +} + + +LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_Equals) +{ + CCNxName *locator = ccnxName_CreateFromCString("ccnx:/my/manifest"); + + CCNxManifestHashGroup *x = _createHashGroup(locator, 10, 0, 0, 0, 0); + CCNxManifestHashGroup *y = _createHashGroup(locator, 10, 0, 0, 0, 0); + CCNxManifestHashGroup *z = _createHashGroup(locator, 10, 0, 0, 0, 0); + + CCNxManifestHashGroup *u1 = _createHashGroup(locator, 5, 0, 0, 0, 0); + CCNxManifestHashGroup *u2 = _createHashGroup(NULL, 10, 0, 0, 0, 0); + CCNxManifestHashGroup *u3 = _createHashGroup(locator, 10, 1, 0, 0, 0); + CCNxManifestHashGroup *u4 = _createHashGroup(locator, 10, 0, 1, 0, 0); + CCNxManifestHashGroup *u5 = _createHashGroup(locator, 10, 0, 0, 1, 0); + CCNxManifestHashGroup *u6 = _createHashGroup(locator, 10, 0, 0, 0, 1); + + parcObjectTesting_AssertEqualsFunction(ccnxManifestHashGroup_Equals, x, y, z, u1, u2, u3, u4, u5, u6, NULL); + + ccnxManifestHashGroup_Release(&x); + ccnxManifestHashGroup_Release(&y); + ccnxManifestHashGroup_Release(&z); + + ccnxManifestHashGroup_Release(&u1); + ccnxManifestHashGroup_Release(&u2); + ccnxManifestHashGroup_Release(&u3); + ccnxManifestHashGroup_Release(&u4); + ccnxManifestHashGroup_Release(&u5); + ccnxManifestHashGroup_Release(&u6); + + ccnxName_Release(&locator); +} + +LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_ToString) +{ + char *jsonString = "{ \"HashGroup\" : [ { \"type\" : 0, \"digest\" : \"617364617364617364\" } ] }"; + PARCJSON *json = parcJSON_ParseString(jsonString); + + CCNxManifestHashGroup *group = ccnxManifestHashGroup_CreateFromJson(json); + + char *stringForm = ccnxManifestHashGroup_ToString(group); + assertTrue(strcmp(jsonString, stringForm) == 0, "Expected %s and actual %s should be equal.", jsonString, stringForm); + + parcMemory_Deallocate(&stringForm); + parcJSON_Release(&json); + ccnxManifestHashGroup_Release(&group); +} + +LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_ToJson) +{ + char *jsonString = "{ \"HashGroup\" : [ { \"type\" : 0, \"digest\" : \"617364617364617364\" } ] }"; + PARCJSON *json = parcJSON_ParseString(jsonString); + + CCNxManifestHashGroup *group = ccnxManifestHashGroup_CreateFromJson(json); + PARCJSON *expected = ccnxManifestHashGroup_ToJson(group); + + assertTrue(parcJSON_Equals(json, expected), "Expected the input and output JSON to be identical"); + + parcJSON_Release(&expected); + parcJSON_Release(&json); + ccnxManifestHashGroup_Release(&group); +} + +LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_IsFull) +{ + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + assertNotNull(group, "Expected non-null CCNxManifestHashGroup"); + + for (size_t i = 0; i < MAX_NUMBER_OF_POINTERS; i++) { + PARCBuffer *buffer = parcBuffer_Allocate(32); + assertTrue(ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, buffer), "Expected the insertion to succeed"); + parcBuffer_Release(&buffer); + } + + PARCBuffer *buffer = parcBuffer_Allocate(32); + assertFalse(ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, buffer), "Expected the insertion to fail since the HashGroup is full."); + parcBuffer_Release(&buffer); + + bool isFull = ccnxManifestHashGroup_IsFull(group); + assertTrue(isFull, "Expected the group to be full after %ul pointers", MAX_NUMBER_OF_POINTERS); + + ccnxManifestHashGroup_Release(&group); +} + +LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_CreateInterestList_OverrideLocator) +{ + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + assertNotNull(group, "Expected non-null CCNxManifestHashGroup"); + + PARCLinkedList *interestList = parcLinkedList_Create(); + CCNxName *locator = ccnxName_CreateFromCString("ccnx:/locator"); + for (size_t i = 0; i < MAX_NUMBER_OF_POINTERS; i++) { + PARCBuffer *buffer = parcBuffer_Allocate(32); + assertTrue(ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, buffer), "Expected the insertion to succeed"); + + CCNxInterest *interest = ccnxInterest_CreateSimple(locator); + ccnxInterest_SetContentObjectHashRestriction(interest, buffer); + parcLinkedList_Append(interestList, interest); + + ccnxInterest_Release(&interest); + parcBuffer_Release(&buffer); + } + + PARCLinkedList *extractedList = ccnxManifestHashGroup_CreateInterestList(group, locator); + assertTrue(parcLinkedList_Equals(interestList, extractedList), "Expected the interest lists to be equal"); + + parcLinkedList_Release(&interestList); + parcLinkedList_Release(&extractedList); + ccnxName_Release(&locator); + ccnxManifestHashGroup_Release(&group); +} + +LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_CreateInterestList_GroupLocator) +{ + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + assertNotNull(group, "Expected non-null CCNxManifestHashGroup"); + + CCNxName *locator = ccnxName_CreateFromCString("ccnx:/group/locator"); + ccnxManifestHashGroup_SetLocator(group, locator); + + PARCLinkedList *interestList = parcLinkedList_Create(); + for (size_t i = 0; i < MAX_NUMBER_OF_POINTERS; i++) { + PARCBuffer *buffer = parcBuffer_Allocate(32); + assertTrue(ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, buffer), "Expected the insertion to succeed"); + + CCNxInterest *interest = ccnxInterest_CreateSimple(locator); + ccnxInterest_SetContentObjectHashRestriction(interest, buffer); + parcLinkedList_Append(interestList, interest); + + ccnxInterest_Release(&interest); + parcBuffer_Release(&buffer); + } + + CCNxName *differentLocator = ccnxName_CreateFromCString("ccnx:/different/locator"); + PARCLinkedList *extractedList = ccnxManifestHashGroup_CreateInterestList(group, differentLocator); + ccnxName_Release(&differentLocator); + assertTrue(parcLinkedList_Equals(interestList, extractedList), "Expected the interest lists to be equal"); + + parcLinkedList_Release(&interestList); + parcLinkedList_Release(&extractedList); + ccnxName_Release(&locator); + ccnxManifestHashGroup_Release(&group); +} + +LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_CreateInterestList_NoLocator) +{ + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + assertNotNull(group, "Expected non-null CCNxManifestHashGroup"); + + for (size_t i = 0; i < MAX_NUMBER_OF_POINTERS; i++) { + PARCBuffer *buffer = parcBuffer_Allocate(32); + assertTrue(ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, buffer), "Expected the insertion to succeed"); + parcBuffer_Release(&buffer); + } + + PARCLinkedList *extractedList = ccnxManifestHashGroup_CreateInterestList(group, NULL); + assertTrue(parcLinkedList_Size(extractedList) == 0, "Expected the interest list to be empty since there was no valid locator"); + + parcLinkedList_Release(&extractedList); + ccnxManifestHashGroup_Release(&group); +} + +LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_BlockSize) +{ + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + assertNotNull(group, "Expected non-null CCNxManifestHashGroup"); + + size_t blockSize = 10; + ccnxManifestHashGroup_SetBlockSize(group, blockSize); + size_t actual = ccnxManifestHashGroup_GetBlockSize(group); + + assertTrue(blockSize == actual, "Expected %zu, got %zu", blockSize, actual); + + ccnxManifestHashGroup_Release(&group); +} + +LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_DataSize) +{ + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + assertNotNull(group, "Expected non-null CCNxManifestHashGroup"); + + size_t dataSize = 10; + ccnxManifestHashGroup_SetDataSize(group, dataSize); + size_t actual = ccnxManifestHashGroup_GetDataSize(group); + + assertTrue(dataSize == actual, "Expected %zu, got %zu", dataSize, actual); + + ccnxManifestHashGroup_Release(&group); +} + +LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_EntrySize) +{ + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + assertNotNull(group, "Expected non-null CCNxManifestHashGroup"); + + size_t entrySize = 10; + ccnxManifestHashGroup_SetEntrySize(group, entrySize); + size_t actual = ccnxManifestHashGroup_GetEntrySize(group); + + assertTrue(entrySize == actual, "Expected %zu, got %zu", entrySize, actual); + + ccnxManifestHashGroup_Release(&group); +} + +LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_TreeHeight) +{ + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + assertNotNull(group, "Expected non-null CCNxManifestHashGroup"); + + size_t treeHeight = 10; + ccnxManifestHashGroup_SetTreeHeight(group, treeHeight); + size_t actual = ccnxManifestHashGroup_GetTreeHeight(group); + + assertTrue(treeHeight == actual, "Expected %zu, got %zu", treeHeight, actual); + + ccnxManifestHashGroup_Release(&group); +} + +LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_OverallDataDigest) +{ + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + assertNotNull(group, "Expected non-null CCNxManifestHashGroup"); + + PARCBuffer *digest = parcBuffer_Allocate(10); + ccnxManifestHashGroup_SetOverallDataDigest(group, digest); + const PARCBuffer *actual = ccnxManifestHashGroup_GetOverallDataDigest(group); + + assertTrue(parcBuffer_Equals(digest, actual) == true, "Expected %s, got %s", parcBuffer_ToHexString(digest), parcBuffer_ToHexString(actual)); + + parcBuffer_Release(&digest); + ccnxManifestHashGroup_Release(&group); +} + +LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_Locator) +{ + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + assertNotNull(group, "Expected non-null CCNxManifestHashGroup"); + + CCNxName *expected = ccnxName_CreateFromCString("ccnx:/flic/manifest"); + ccnxManifestHashGroup_SetLocator(group, expected); + const CCNxName *actual = ccnxManifestHashGroup_GetLocator(group); + + assertTrue(ccnxName_Equals(expected, actual) == true, "Expected %s, got %s", ccnxName_ToString(expected), ccnxName_ToString(actual)); + + ccnxName_Release(&expected); + ccnxManifestHashGroup_Release(&group); +} + +LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_HasMetadata) +{ + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + assertNotNull(group, "Expected non-null CCNxManifestHashGroup"); + + assertFalse(ccnxManifestHashGroup_HasMetadata(group), "Expected an empty HashGroup to have no metadata"); + + CCNxName *expected = ccnxName_CreateFromCString("ccnx:/flic/manifest"); + ccnxManifestHashGroup_SetLocator(group, expected); + + assertTrue(ccnxManifestHashGroup_HasMetadata(group), "Expected a HashGroup with a locator to have metadata"); + + ccnxName_Release(&expected); + ccnxManifestHashGroup_Release(&group); +} + +LONGBOW_TEST_CASE(Global, ccnxManifestHashGroup_Iterator) +{ + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + assertNotNull(group, "Expected non-null CCNxManifestHashGroup"); + + for (size_t i = 0; i < MAX_NUMBER_OF_POINTERS; i++) { + PARCBuffer *buffer = parcBuffer_Allocate(10); + parcBuffer_Flip(parcBuffer_PutUint32(buffer, i)); + assertTrue(ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, buffer), "Expected the insertion to succeed"); + parcBuffer_Release(&buffer); + } + + PARCIterator *itr = ccnxManifestHashGroup_Iterator(group); + + size_t i = 0; + while (parcIterator_HasNext(itr)) { + CCNxManifestHashGroupPointer *ptr = (CCNxManifestHashGroupPointer *) parcIterator_Next(itr); + const PARCBuffer *digest = ccnxManifestHashGroupPointer_GetDigest(ptr); + size_t index = parcBuffer_GetUint32((PARCBuffer *) digest); + assertTrue(index == i, "Expected the right digest pointer to be extracted, got %zu, expected %zu", index, i); + i++; + } + + parcIterator_Release(&itr); + + bool isFull = ccnxManifestHashGroup_IsFull(group); + assertTrue(isFull, "Expected the group to be full after %ul pointers", MAX_NUMBER_OF_POINTERS); + + ccnxManifestHashGroup_Release(&group); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_ManifestHashGroup); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/test/test_ccnx_Name.c b/libccnx-common/ccnx/common/test/test_ccnx_Name.c new file mode 100644 index 00000000..2adec939 --- /dev/null +++ b/libccnx-common/ccnx/common/test/test_ccnx_Name.c @@ -0,0 +1,735 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +#include "../ccnx_Name.c" + +#include <LongBow/unit-test.h> + +#include <stdio.h> +#include <limits.h> + +#include <parc/algol/parc_SafeMemory.h> + +LONGBOW_TEST_RUNNER(ccnx_Name) +{ + LONGBOW_RUN_TEST_FIXTURE(Local); + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Specialization); + LONGBOW_RUN_TEST_FIXTURE(Performance); +} + +LONGBOW_TEST_RUNNER_SETUP(ccnx_Name) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_Name) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxName_CreateFromCString); + LONGBOW_RUN_TEST_CASE(Global, ccnxName_CreateFromCString_Root); + LONGBOW_RUN_TEST_CASE(Global, ccnxName_CreateFromCString_BadScheme); + LONGBOW_RUN_TEST_CASE(Global, ccnxName_CreateFromCString_NoScheme); + LONGBOW_RUN_TEST_CASE(Global, ccnxName_CreateFromCString_ZeroComponents); + LONGBOW_RUN_TEST_CASE(Global, ccnxName_CreateFromBuffer); + + LONGBOW_RUN_TEST_CASE(Global, ccnxName_IsValid_True); + LONGBOW_RUN_TEST_CASE(Global, ccnxName_IsValid_False); + + LONGBOW_RUN_TEST_CASE(Global, ccnxName_Equals); + LONGBOW_RUN_TEST_CASE(Global, ccnxName_HashCode); + LONGBOW_RUN_TEST_CASE(Global, ccnxName_LeftMostHashCode); + LONGBOW_RUN_TEST_CASE(Global, ccnxName_HashCode_LeftMostHashCode); + + LONGBOW_RUN_TEST_CASE(Global, ccnxName_ToString); + LONGBOW_RUN_TEST_CASE(Global, ccnxName_ToString_Root); + LONGBOW_RUN_TEST_CASE(Global, ccnxName_ToString_NoPath); + LONGBOW_RUN_TEST_CASE(Global, ccnxName_ToString_LCI); + LONGBOW_RUN_TEST_CASE(Global, ccnxName_Copy_Zero); + LONGBOW_RUN_TEST_CASE(Global, ccnxName_Copy_NonZero); + LONGBOW_RUN_TEST_CASE(Global, ccnxName_CreateAndDestroy); + + LONGBOW_RUN_TEST_CASE(Global, ccnxName_Trim); + LONGBOW_RUN_TEST_CASE(Global, ccnxName_Trim_MAXINT); + LONGBOW_RUN_TEST_CASE(Global, ccnxName_StartsWith_True); + LONGBOW_RUN_TEST_CASE(Global, ccnxName_StartsWith_FalseShorterPrefix); + LONGBOW_RUN_TEST_CASE(Global, ccnxName_StartsWith_FalseLongerPrefix); + + LONGBOW_RUN_TEST_CASE(Global, ccnxName_Compare); + LONGBOW_RUN_TEST_CASE(Global, ccnxName_ComposeNAME); + + LONGBOW_RUN_TEST_CASE(Global, ParseTest1); + LONGBOW_RUN_TEST_CASE(Global, ParseTest2); + + LONGBOW_RUN_TEST_CASE(Global, MemoryProblem); +} + +static size_t _longBowGlobal_Global_outstanding; + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + _longBowGlobal_Global_outstanding = parcMemory_Outstanding(); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + LongBowStatus result = LONGBOW_STATUS_SUCCEEDED; + + size_t allocationsLeaked = parcMemory_Outstanding() - _longBowGlobal_Global_outstanding; + + if (allocationsLeaked > 0) { + printf("%s leaks memory by %zd allocations\n", longBowTestCase_GetName(testCase), allocationsLeaked); + parcSafeMemory_ReportAllocation(STDERR_FILENO); + result = LONGBOW_STATUS_MEMORYLEAK; + } + return result; +} + +LONGBOW_TEST_CASE(Global, ccnxName_ComposeNAME) +{ + char *string = "lci:/a/b/c"; + + CCNxName *basename = ccnxName_CreateFromCString("lci:/a/b"); + CCNxName *expected = ccnxName_CreateFromCString(string); + + CCNxName *actual = ccnxName_ComposeNAME(basename, "c"); + assertTrue(ccnxName_Equals(expected, actual), "Failed."); + + ccnxName_Release(&basename); + ccnxName_Release(&expected); + ccnxName_Release(&actual); +} + +LONGBOW_TEST_CASE(Global, ccnxName_IsValid_True) +{ + char *string = "lci:/a/b/c"; + CCNxName *name = ccnxName_CreateFromCString(string); + assertTrue(ccnxName_IsValid(name), "Expected %s to be a valid CCNxName.", string); + ccnxName_Release(&name); +} + +LONGBOW_TEST_CASE(Global, ccnxName_IsValid_False) +{ + assertFalse(ccnxName_IsValid(NULL), "Expected NULL to be an invalid CCNxName."); +} + +LONGBOW_TEST_CASE(Global, ccnxName_Equals) +{ + CCNxName *x = ccnxName_CreateFromCString("lci:/a/b/c"); + CCNxName *y = ccnxName_CreateFromCString("lci:/a/b/c"); + CCNxName *z = ccnxName_CreateFromCString("lci:/a/b/c"); + CCNxName *u1 = ccnxName_CreateFromCString("lci:/a/b"); + CCNxName *u2 = ccnxName_CreateFromCString("lci:/a/b/d"); + + assertEqualsContract(ccnxName_Equals, x, y, z, u1, u2); + + ccnxName_Release(&x); + ccnxName_Release(&y); + ccnxName_Release(&z); + ccnxName_Release(&u1); + ccnxName_Release(&u2); +} + +LONGBOW_TEST_CASE(Global, ccnxName_ToString_Root) +{ + const char *expected = "ccnx:/"; + + CCNxName *name = ccnxName_CreateFromCString(expected); + + char *actual = ccnxName_ToString(name); + + assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual); + parcMemory_Deallocate((void **) &actual); + + ccnxName_Release(&name); + + name = ccnxName_CreateFromCString("ccnx:"); + actual = ccnxName_ToString(name); + + assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual); + parcMemory_Deallocate((void **) &actual); + + ccnxName_Release(&name); +} + +LONGBOW_TEST_CASE(Global, ccnxName_ToString_NoPath) +{ + const char *expected = "ccnx:/"; + + CCNxName *name = ccnxName_CreateFromCString("ccnx:"); + + char *actual = ccnxName_ToString(name); + + assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual); + parcMemory_Deallocate((void **) &actual); + + ccnxName_Release(&name); +} + +LONGBOW_TEST_CASE(Global, ccnxName_Trim) +{ + CCNxName *name = ccnxName_CreateFromCString("ccnx:/a/b/c"); + + ccnxName_Trim(name, 1); + + const char *expected = "ccnx:/a/b"; + char *actual = ccnxName_ToString(name); + + assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual); + + parcMemory_Deallocate((void **) &actual); + + ccnxName_Release(&name); +} + +LONGBOW_TEST_CASE(Global, ccnxName_Trim_MAXINT) +{ + CCNxName *name = ccnxName_CreateFromCString("ccnx:/a/b/c"); + + ccnxName_Trim(name, INT_MAX); + + const char *expected = "ccnx:/"; + char *actual = ccnxName_ToString(name); + + assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual); + + parcMemory_Deallocate((void **) &actual); + + ccnxName_Release(&name); +} + +LONGBOW_TEST_CASE(Global, ccnxName_Copy_Zero) +{ + const char *uri = "ccnx:/"; // A Name with 1 zero-length segment + + CCNxName *name = ccnxName_CreateFromCString(uri); + + CCNxName *copy = ccnxName_Copy(name); + assertNotNull(copy, "Expect non-null result."); + + char *expected = ccnxName_ToString(name); + char *actual = ccnxName_ToString(copy); + + assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual); + + ccnxName_Release(&name); + ccnxName_Release(©); + parcMemory_Deallocate((void **) &expected); + parcMemory_Deallocate((void **) &actual); +} + +LONGBOW_TEST_CASE(Global, ccnxName_Copy_NonZero) +{ + const char *uri = "ccnx:/a/b/c/d/e"; + + CCNxName *name = ccnxName_CreateFromCString(uri); + + CCNxName *copy = ccnxName_Copy(name); + assertNotNull(copy, "Expect non-null result."); + + char *expected = ccnxName_ToString(name); + char *actual = ccnxName_ToString(copy); + + assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual); + + ccnxName_Release(&name); + ccnxName_Release(©); + parcMemory_Deallocate((void **) &expected); + parcMemory_Deallocate((void **) &actual); +} + +LONGBOW_TEST_CASE(Global, ccnxName_HashCode) +{ + const char *uriA = "lci:/a/b/c/d/e/"; + const char *uriB = "lci:/a/b/c/d/e/"; + + CCNxName *nameA = ccnxName_CreateFromCString(uriA); + CCNxName *nameB = ccnxName_CreateFromCString(uriB); + + PARCHashCode codeA = ccnxName_HashCode(nameA); + PARCHashCode codeB = ccnxName_HashCode(nameB); + + // We know the hashcode of uriA is not zero + assertTrue(codeA != 0, "Expected a non-zero hash code"); + + assertTrue(codeA == codeB, "Expected %" PRIPARCHashCode " == %" PRIPARCHashCode, codeA, codeB); + + ccnxName_Release(&nameA); + ccnxName_Release(&nameB); +} + +LONGBOW_TEST_CASE(Global, ccnxName_HashCode_LeftMostHashCode) +{ + const char *uriA = "lci:/a/b/c/d/e/"; + const char *uriB = "lci:/a/b/c/d/e/"; + + CCNxName *nameA = ccnxName_CreateFromCString(uriA); + CCNxName *nameB = ccnxName_CreateFromCString(uriB); + + PARCHashCode codeA = ccnxName_HashCode(nameA); + PARCHashCode codeB = ccnxName_HashCode(nameB); + PARCHashCode leftMostCodeA = ccnxName_LeftMostHashCode(nameA, INT_MAX); + PARCHashCode leftMostCodeB = ccnxName_LeftMostHashCode(nameB, INT_MAX); + + // We know the hashcode of uriA is not zero + assertTrue(codeA != 0, "Expected a non-zero hash code"); + + assertTrue(codeA == codeB, "Expected %" PRIPARCHashCode " == %" PRIPARCHashCode, codeA, codeB); + assertTrue(codeA == leftMostCodeA, "Expected %" PRIPARCHashCode " == %" PRIPARCHashCode, codeA, leftMostCodeA); + assertTrue(codeA == leftMostCodeB, "Expected %" PRIPARCHashCode " == %" PRIPARCHashCode, codeA, leftMostCodeB); + + ccnxName_Release(&nameA); + ccnxName_Release(&nameB); +} + +LONGBOW_TEST_CASE(Global, ccnxName_LeftMostHashCode) +{ + const char *uriA = "lci:/a/b/c/d/e/"; + const char *uriB = "lci:/a/b/c/d/e/"; + + CCNxName *nameA = ccnxName_CreateFromCString(uriA); + CCNxName *nameB = ccnxName_CreateFromCString(uriB); + + PARCHashCode codeA = ccnxName_LeftMostHashCode(nameA, 2); + PARCHashCode codeB = ccnxName_LeftMostHashCode(nameB, 2); + + assertTrue(codeA == codeB, "Expected %" PRIPARCHashCode " == %" PRIPARCHashCode, codeA, codeB); + + ccnxName_Release(&nameA); + ccnxName_Release(&nameB); +} + +LONGBOW_TEST_CASE(Global, ccnxName_CreateAndDestroy) +{ + CCNxName *name = ccnxName_Create(); + assertNotNull(name, "Expected non-null"); + ccnxName_Release(&name); + assertNull(name, "Expected null"); +} + +LONGBOW_TEST_CASE(Global, ccnxName_CreateFromCString) +{ + const char *uri = "lci:/CCN-Python-Test"; + + CCNxName *name = ccnxName_CreateFromCString(uri); + ccnxName_Display(name, 0); + assertNotNull(name, "Expected non-null"); + + size_t expected = 1; + size_t actual = ccnxName_GetSegmentCount(name); + + assertTrue(expected == actual, "Expected %zd segments, actual %zd", expected, actual); + + ccnxName_Release(&name); +} + +LONGBOW_TEST_CASE(Global, ccnxName_CreateFromCString_BadScheme) +{ + const char *uri = "abcd:/CCN-Python-Test/Echo"; + + CCNxName *name = ccnxName_CreateFromCString(uri); + assertNull(name, "Expected null"); +} + +LONGBOW_TEST_CASE(Global, ccnxName_CreateFromCString_NoScheme) +{ + const char *uri = "/paravion"; + + CCNxName *name = ccnxName_CreateFromCString(uri); + assertNull(name, "Expected null"); +} + +LONGBOW_TEST_CASE(Global, ccnxName_CreateFromCString_ZeroComponents) +{ + const char *uri = "lci:"; + + CCNxName *name = ccnxName_CreateFromCString(uri); + assertNotNull(name, "Expected non-null result from ccnxName_CreateFromCString"); + + size_t expected = 0; + size_t actual = ccnxName_GetSegmentCount(name); + + assertTrue(expected == actual, "Expected %zd segments, actual %zd", expected, actual); + + ccnxName_Release(&name); +} + +LONGBOW_TEST_CASE(Global, ccnxName_CreateFromCString_Root) +{ + const char *uri = "lci:/"; + + CCNxName *name = ccnxName_CreateFromCString(uri); + assertNotNull(name, "Expected non-null"); + + size_t expected = 1; + size_t actual = ccnxName_GetSegmentCount(name); + + assertTrue(expected == actual, "Expected %zd segments, actual %zd", expected, actual); + + CCNxNameSegment *segment = ccnxName_GetSegment(name, 0); + + size_t segmentLength = ccnxNameSegment_Length(segment); + assertTrue(segmentLength == 0, "Expected a zero length segment, actual %zd", segmentLength); + + ccnxName_Release(&name); +} + +LONGBOW_TEST_CASE(Global, ccnxName_CreateFromBuffer) +{ + PARCBuffer *buffer = parcBuffer_WrapCString("lci:/CCN-Python-Test"); + CCNxName *name = ccnxName_CreateFromBuffer(buffer); + assertNotNull(name, "Expected non-null"); + + size_t expected = 1; + size_t actual = ccnxName_GetSegmentCount(name); + + assertTrue(expected == actual, "Expected %zd segments, actual %zd", expected, actual); + + ccnxName_Release(&name); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxName_ToString_LCI) +{ + const char *lci = "lci:/a/b"; + const char *expectedURI = "ccnx:/a/b"; + + CCNxName *name = ccnxName_CreateFromCString(lci); + + size_t expected = 2; + size_t actual = ccnxName_GetSegmentCount(name); + + assertTrue(expected == actual, + "Expected %zd segments, actual %zd", expected, actual); + + char *string = ccnxName_ToString(name); + assertTrue(strcmp(expectedURI, string) == 0, + "Expected '%s' actual '%s'", expectedURI, string); + parcMemory_Deallocate((void **) &string); + + ccnxName_Release(&name); +} + +LONGBOW_TEST_CASE(Global, ccnxName_ToString) +{ + const char *uri = "ccnx:/a/b"; + + CCNxName *name = ccnxName_CreateFromCString(uri); + + size_t expected = 2; + size_t actual = ccnxName_GetSegmentCount(name); + + assertTrue(expected == actual, + "Expected %zd segments, actual %zd", expected, actual); + + char *string = ccnxName_ToString(name); + assertTrue(strcmp(uri, string) == 0, + "Expected '%s' actual '%s'", uri, string); + parcMemory_Deallocate((void **) &string); + + ccnxName_Release(&name); +} + +LONGBOW_TEST_CASE(Global, ccnxName_Compare) +{ + CCNxName *value = ccnxName_CreateFromCString("lci:/a/b/c"); + CCNxName *equal1 = ccnxName_CreateFromCString("lci:/a/b/c"); + + CCNxName **equivalents = (CCNxName *[]) { + equal1, + NULL + }; + + CCNxName *lesser1 = ccnxName_CreateFromCString("lci:/a/b"); + CCNxName *lesser2 = ccnxName_CreateFromCString("lci:/a/b/b"); + CCNxName **lesser = (CCNxName *[]) { + lesser1, + lesser2, + NULL + }; + + CCNxName *greater1 = ccnxName_CreateFromCString("lci:/a/b/d"); + CCNxName *greater2 = ccnxName_CreateFromCString("lci:/a/b/c/d"); + CCNxName **greater = (CCNxName *[]) { + greater1, + greater2, + NULL + }; + + assertCompareToContract(ccnxName_Compare, value, equivalents, lesser, greater); + + for (int i = 0; lesser[i] != NULL; i++) { + ccnxName_Release(&lesser[i]); + } + for (int i = 0; greater[i] != NULL; i++) { + ccnxName_Release(&greater[i]); + } + for (int i = 0; equivalents[i] != NULL; i++) { + ccnxName_Release(&equivalents[i]); + } + ccnxName_Release(&value); +} + +LONGBOW_TEST_CASE(Global, ccnxName_StartsWith_True) +{ + const char *uriA = "lci:/a/b/c/d/e/"; + const char *uriB = "lci:/a/b/c/d/e/"; + + CCNxName *nameA = ccnxName_CreateFromCString(uriA); + CCNxName *nameB = ccnxName_CreateFromCString(uriB); + + bool actual = ccnxName_StartsWith(nameA, nameA); + + assertTrue(actual, "Expected true"); + + ccnxName_Release(&nameA); + ccnxName_Release(&nameB); +} + +LONGBOW_TEST_CASE(Global, ccnxName_StartsWith_FalseShorterPrefix) +{ + const char *uriA = "lci:/a/b/c/d/e"; + const char *prefix = "lci:/a/b/d"; + + CCNxName *nameA = ccnxName_CreateFromCString(uriA); + CCNxName *nameB = ccnxName_CreateFromCString(prefix); + + bool actual = ccnxName_StartsWith(nameA, nameB); + + assertFalse(actual, "Expected false"); + + ccnxName_Release(&nameA); + ccnxName_Release(&nameB); +} + +LONGBOW_TEST_CASE(Global, ccnxName_StartsWith_FalseLongerPrefix) +{ + const char *uriA = "lci:/a/b/c/d/e"; + const char *prefix = "lci:/a/b/c/d/e/f"; + + CCNxName *nameA = ccnxName_CreateFromCString(uriA); + CCNxName *nameB = ccnxName_CreateFromCString(prefix); + + bool actual = ccnxName_StartsWith(nameA, nameB); + + assertFalse(actual, "Expected false"); + + ccnxName_Release(&nameA); + ccnxName_Release(&nameB); +} + +static CCNxNameSegment * +createSegment(PARCBuffer *buffer, size_t start, size_t end) +{ + parcBuffer_SetPosition(buffer, start); + PARCBuffer *slice = parcBuffer_Slice(buffer); + parcBuffer_SetLimit(slice, end); + + CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, slice); + parcBuffer_Release(&slice); + + return segment; +} + +LONGBOW_TEST_CASE(Global, MemoryProblem) +{ + char memory[] = "abcdefghijklmnopqrstuvwxyz"; + PARCBuffer *buffer = parcBuffer_Wrap(memory, sizeof(memory), 0, sizeof(memory)); + + CCNxName *name = ccnxName_Create(); + + CCNxNameSegment *segment1 = createSegment(buffer, 2, 4); // "cd" + ccnxName_Append(name, segment1); + + CCNxNameSegment *segment2 = createSegment(buffer, 10, 14); // "klmn" + ccnxName_Append(name, segment2); + + CCNxName *name2 = ccnxName_Acquire(name); + + parcBuffer_Release(&buffer); + ccnxName_Release(&name2); + + ccnxName_Release(&name); + ccnxNameSegment_Release(&segment1); + ccnxNameSegment_Release(&segment2); +} + +LONGBOW_TEST_CASE(Global, ParseTest1) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/" CCNxNameLabel_Name "=foot/3=toe/4=nail"); + assertNotNull(name, "Expected non-null value from ccnxName_CreateFromCString"); + + ccnxName_Display(name, 0); + + ccnxName_Release(&name); +} + +LONGBOW_TEST_CASE(Global, ParseTest2) +{ + CCNxName *a = ccnxName_CreateFromCString("lci:/a/b/c"); + CCNxName *b = ccnxName_CreateFromCString("lci:/Name=a/Name=b/Name=c"); + assertTrue(ccnxName_Equals(a, b), "Expected to be equal"); + ccnxName_Release(&a); + ccnxName_Release(&b); + + char *expected = "ccnx:/test/Name=MiISAg%3D%3D"; + CCNxName *name = ccnxName_CreateFromCString(expected); + assertNotNull(name, "Expected non-null value from ccnxName_CreateFromCString"); + char *actual = ccnxName_ToString(name); + printf("%s\n", actual); + assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual); + parcMemory_Deallocate(&actual); + + ccnxName_Display(name, 0); + + ccnxName_Release(&name); +} + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Specialization) +{ + LONGBOW_RUN_TEST_CASE(Specialization, ccnxName_Prefix); + LONGBOW_RUN_TEST_CASE(Specialization, ccnxName_Prefix_Excess); + LONGBOW_RUN_TEST_CASE(Specialization, ccnxName_Prefix_0); +} + +LONGBOW_TEST_FIXTURE_SETUP(Specialization) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Specialization, ccnxName_Prefix) +{ + CCNxName *a = ccnxName_CreateFromCString("ccnx:/a/b/c"); + CCNxName *expected = ccnxName_CreateFromCString("ccnx:/a"); + + CCNxName *actual = ccnxName_CreatePrefix(a, 1); + + assertTrue(ccnxName_Equals(expected, actual), "Mismatched results."); + + ccnxName_Release(&a); + ccnxName_Release(&expected); + ccnxName_Release(&actual); +} + +LONGBOW_TEST_CASE(Specialization, ccnxName_Prefix_Excess) +{ + CCNxName *a = ccnxName_CreateFromCString("ccnx:/a/b/c"); + CCNxName *expected = ccnxName_CreateFromCString("ccnx:/a/b/c"); + + CCNxName *actual = ccnxName_CreatePrefix(a, 100); + + assertTrue(ccnxName_Equals(expected, actual), "Mismatched results."); + + ccnxName_Release(&a); + ccnxName_Release(&expected); + ccnxName_Release(&actual); +} + +LONGBOW_TEST_CASE(Specialization, ccnxName_Prefix_0) +{ + CCNxName *a = ccnxName_CreateFromCString("ccnx:/a/b/c"); + CCNxName *expected = ccnxName_CreateFromCString("ccnx:"); + + CCNxName *actual = ccnxName_CreatePrefix(a, 0); + + assertTrue(ccnxName_Equals(expected, actual), "Mismatched results."); + + ccnxName_Release(&a); + ccnxName_Release(&expected); + ccnxName_Release(&actual); +} + +LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false) +{ + LONGBOW_RUN_TEST_CASE(Performance, ccnxName_Create); +} + +LONGBOW_TEST_FIXTURE_SETUP(Performance) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Performance) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Performance, ccnxName_Create) +{ + PARCBuffer *value = parcBuffer_WrapCString("Hello"); + + for (int i = 0; i < 10000; i++) { + CCNxName *name = ccnxName_Create(); + CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, value); + for (int j = 0; j < 1000; j++) { + ccnxName_Append(name, segment); + } + ccnxNameSegment_Release(&segment); + ccnxName_Release(&name); + } + parcBuffer_Release(&value); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_Name); + int exitStatus = longBowMain(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/test/test_ccnx_NameLabel.c b/libccnx-common/ccnx/common/test/test_ccnx_NameLabel.c new file mode 100755 index 00000000..428c2f29 --- /dev/null +++ b/libccnx-common/ccnx/common/test/test_ccnx_NameLabel.c @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ +#include "../ccnx_NameLabel.c" + +#include <LongBow/unit-test.h> +#include <stdio.h> +#include <parc/algol/parc_SafeMemory.h> +#include <parc/testing/parc_ObjectTesting.h> + + +LONGBOW_TEST_RUNNER(ccnx_NameType) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Errors); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnx_NameType) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_NameType) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxNameLabel_Create); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameLabel_AcquireRelease); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameLabel_GetType); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameLabel_GetParameter); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameLabel_Equals); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameLabel_Copy); + + LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Resolve_Mnemonic); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Resolve_Mnemonic_NULL); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Resolve_Mnemonic_Empty); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Resolve_Mnemonic_App0); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Resolve_Mnemonic_App); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Resolve_Numeric_Decimal); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Resolve_Numeric_Hex); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Resolve_Unknown_Mnemonic); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_BuildString_KnownLabel); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_BuildString_UnknownLabel); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_BuildString_AppLabel); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_BuildString_AppLabel4096); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Parse); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Parse_DefaultLabel); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Parse_EmptyLabel); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Parse_KnownLabel); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Parse_DecimalParameterLabel); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Parse_HexadecimalParameterLabel); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Parse_OutOfRangeLabel); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Parse_BadHexLabel); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameType_Parse_UknownMnemonicLabel); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxNameType_Resolve_Mnemonic) +{ + char *mnemonic = "Name"; + PARCBuffer *label = parcBuffer_WrapCString(mnemonic); + CCNxNameLabelType actual = _ccnxNameLabelType_Resolve(label); + assertTrue(actual == CCNxNameLabelType_NAME, + "Expected an CCNxNameType_NAME type for the mnemonic '%s'", mnemonic); + parcBuffer_Release(&label); +} + +LONGBOW_TEST_CASE(Global, ccnxNameType_Resolve_Mnemonic_NULL) +{ + CCNxNameLabelType actual = _ccnxNameLabelType_Resolve(NULL); + assertTrue(actual == CCNxNameLabelType_NAME, + "Expected an CCNxNameType_NAME type for a NULL mnemonic."); +} + +LONGBOW_TEST_CASE(Global, ccnxNameType_Resolve_Mnemonic_Empty) +{ + PARCBuffer *label = parcBuffer_Allocate(0); + CCNxNameLabelType actual = _ccnxNameLabelType_Resolve(label); + assertTrue(actual == CCNxNameLabelType_NAME, + "Expected an CCNxNameType_NAME type for an empty mnemonic."); + parcBuffer_Release(&label); +} + +LONGBOW_TEST_CASE(Global, ccnxNameType_Resolve_Mnemonic_App0) +{ + PARCBuffer *label = parcBuffer_WrapCString("app"); + CCNxNameLabelType actual = _ccnxNameLabelType_Resolve(label); + assertTrue(actual == CCNxNameLabelType_App(0), + "Expected 0x%04x type, actual 0x%04x", CCNxNameLabelType_App(0), actual); + parcBuffer_Release(&label); +} + +LONGBOW_TEST_CASE(Global, ccnxNameType_Resolve_Mnemonic_App) +{ + PARCBuffer *label = parcBuffer_WrapCString("app"); + CCNxNameLabelType actual = _ccnxNameLabelType_Resolve(label); + assertTrue(actual == CCNxNameLabelType_App(0), + "Expected 0x%04x type, actual 0x%04x", CCNxNameLabelType_App(0), actual); + parcBuffer_Release(&label); +} + +LONGBOW_TEST_CASE(Global, ccnxNameType_Resolve_Numeric_Decimal) +{ + PARCBuffer *label = parcBuffer_WrapCString("16"); + CCNxNameLabelType actual = _ccnxNameLabelType_Resolve(label); + assertTrue(actual == CCNxNameLabelType_CHUNK, + "Expected type %d, actual %d", CCNxNameLabelType_CHUNK, actual); + parcBuffer_Release(&label); +} + +LONGBOW_TEST_CASE(Global, ccnxNameType_Resolve_Numeric_Hex) +{ + CCNxNameLabelType expected = 0xF000; + PARCBuffer *label = parcBuffer_WrapCString("0xF000"); + CCNxNameLabelType actual = _ccnxNameLabelType_Resolve(label); + assertTrue(actual == expected, + "Expected type %d, actual %d", expected, actual); + parcBuffer_Release(&label); +} + +LONGBOW_TEST_CASE(Global, ccnxNameType_Resolve_Unknown_Mnemonic) +{ + CCNxNameLabelType expected = CCNxNameLabelType_Unknown; + PARCBuffer *label = parcBuffer_WrapCString("xyzzy"); + CCNxNameLabelType actual = _ccnxNameLabelType_Resolve(label); + assertTrue(actual == expected, + "Expected type %d, actual %d", expected, actual); + parcBuffer_Release(&label); +} + +LONGBOW_TEST_CASE(Global, ccnxNameType_BuildString_KnownLabel) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + + CCNxNameLabel *label = ccnxNameLabel_Create(CCNxNameLabelType_CHUNK, NULL); + ccnxNameLabel_BuildString(label, composer); + ccnxNameLabel_Release(&label); + + PARCBuffer *expected = parcBuffer_WrapCString(CCNxNameLabel_Chunk "="); + PARCBuffer *actual = parcBuffer_Flip(parcBufferComposer_GetBuffer(composer)); + + assertTrue(parcBuffer_Equals(expected, actual), + "Expected a successful label lookup."); + parcBuffer_Release(&expected); + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, ccnxNameType_BuildString_UnknownLabel) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + CCNxNameLabel *label = ccnxNameLabel_Create(1111, NULL); + ccnxNameLabel_BuildString(label, composer); + ccnxNameLabel_Release(&label); + + PARCBuffer *expected = parcBuffer_WrapCString("1111" "="); + PARCBuffer *actual = parcBuffer_Flip(parcBufferComposer_GetBuffer(composer)); + + assertTrue(parcBuffer_Equals(expected, actual), + "Expected a successful label lookup."); + + parcBuffer_Release(&expected); + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, ccnxNameType_BuildString_AppLabel) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + + PARCBuffer *parameter = parcBuffer_WrapCString("0"); + CCNxNameLabel *label = ccnxNameLabel_Create(CCNxNameLabelType_App(0), parameter); + ccnxNameLabel_BuildString(label, composer); + ccnxNameLabel_Release(&label); + parcBuffer_Release(¶meter); + + PARCBuffer *expected = parcBuffer_WrapCString("App:0" "="); + PARCBuffer *actual = parcBuffer_Flip(parcBufferComposer_GetBuffer(composer)); + + assertTrue(parcBuffer_Equals(expected, actual), + "Expected a successful label lookup."); + + parcBuffer_Release(&expected); + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, ccnxNameType_BuildString_AppLabel4096) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + PARCBuffer *parameter = parcBuffer_WrapCString("4096"); + CCNxNameLabel *label = ccnxNameLabel_Create(CCNxNameLabelType_App(4096), parameter); + ccnxNameLabel_BuildString(label, composer); + + ccnxNameLabel_Release(&label); + parcBuffer_Release(¶meter); + + PARCBuffer *expected = parcBuffer_WrapCString("App:4096" "="); + PARCBuffer *actual = parcBuffer_Flip(parcBufferComposer_GetBuffer(composer)); + + assertTrue(parcBuffer_Equals(expected, actual), + "Expected a successful label lookup."); + + parcBuffer_Release(&expected); + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, ccnxNameLabel_GetType) +{ + CCNxNameLabelType type = CCNxNameLabelType_NAME; + PARCBuffer *parameter = parcBuffer_WrapCString("Hello"); + CCNxNameLabel *label = ccnxNameLabel_Create(type, parameter); + + CCNxNameLabelType actual = ccnxNameLabel_GetType(label); + + assertTrue(type == actual, "Expected type %u, actual %u", type, actual); + + parcBuffer_Release(¶meter); + ccnxNameLabel_Release(&label); +} + +LONGBOW_TEST_CASE(Global, ccnxNameLabel_GetParameter) +{ + CCNxNameLabelType type = CCNxNameLabelType_NAME; + PARCBuffer *parameter = parcBuffer_WrapCString("Hello"); + CCNxNameLabel *label = ccnxNameLabel_Create(type, parameter); + PARCBuffer *actual = ccnxNameLabel_GetParameter(label); + + assertTrue(parcBuffer_Equals(parameter, actual), "Expected parameter to be equal to the initial parameter."); + parcBuffer_Release(¶meter); + ccnxNameLabel_Release(&label); +} + +LONGBOW_TEST_CASE(Global, ccnxNameLabel_Create) +{ + CCNxNameLabelType type = CCNxNameLabelType_NAME; + PARCBuffer *parameter = parcBuffer_WrapCString("Hello"); + CCNxNameLabel *label = ccnxNameLabel_Create(type, parameter); + parcBuffer_Release(¶meter); + ccnxNameLabel_Release(&label); +} + +LONGBOW_TEST_CASE(Global, ccnxNameLabel_Copy) +{ + PARCBuffer *parameter = parcBuffer_WrapCString("Hello"); + CCNxNameLabel *label = ccnxNameLabel_Create(CCNxNameLabelType_NAME, parameter); + parcBuffer_Release(¶meter); + + CCNxNameLabel *copy = ccnxNameLabel_Copy(label); + + assertTrue(ccnxNameLabel_Equals(label, copy), "Expected copy to the equal to the original."); + + assertTrue(label != copy, "Expected a copy to be distinct from the original."); + ccnxNameLabel_Release(&label); + ccnxNameLabel_Release(©); +} + +LONGBOW_TEST_CASE(Global, ccnxNameLabel_Equals) +{ + PARCBuffer *parameter = parcBuffer_WrapCString("Hello"); + CCNxNameLabel *x = ccnxNameLabel_Create(CCNxNameLabelType_SERIAL, parameter); + parcBuffer_Release(¶meter); + + parameter = parcBuffer_WrapCString("Hello"); + CCNxNameLabel *y = ccnxNameLabel_Create(CCNxNameLabelType_SERIAL, parameter); + parcBuffer_Release(¶meter); + + parameter = parcBuffer_WrapCString("Hello"); + CCNxNameLabel *z = ccnxNameLabel_Create(CCNxNameLabelType_SERIAL, parameter); + parcBuffer_Release(¶meter); + + parameter = parcBuffer_WrapCString("Hello"); + CCNxNameLabel *u1 = ccnxNameLabel_Create(CCNxNameLabelType_CHUNK, parameter); + parcBuffer_Release(¶meter); + + parameter = parcBuffer_WrapCString("Goodbye"); + CCNxNameLabel *u2 = ccnxNameLabel_Create(CCNxNameLabelType_SERIAL, parameter); + parcBuffer_Release(¶meter); + + assertEqualsContract(ccnxNameLabel_Equals, x, y, z, u1, u2, NULL); + + ccnxNameLabel_Release(&x); + ccnxNameLabel_Release(&y); + ccnxNameLabel_Release(&z); + ccnxNameLabel_Release(&u1); + ccnxNameLabel_Release(&u2); +} + +LONGBOW_TEST_CASE(Global, ccnxNameLabel_AcquireRelease) +{ + CCNxNameLabelType type = CCNxNameLabelType_NAME; + PARCBuffer *parameter = parcBuffer_WrapCString("Hello"); + CCNxNameLabel *label = ccnxNameLabel_Create(type, parameter); + + parcObjectTesting_AssertAcquireReleaseContract(ccnxNameLabel_Acquire, label); + + parcBuffer_Release(¶meter); + ccnxNameLabel_Release(&label); +} + +LONGBOW_TEST_CASE(Global, ccnxNameType_Parse) +{ + char *expected = "App:1=value"; + PARCBuffer *buffer = parcBuffer_WrapCString(expected); + CCNxNameLabel *label = ccnxNameLabel_Parse(buffer); + char *actual = ccnxNameLabel_ToString(label); + assertTrue(parcBuffer_Position(buffer) == 6, "Expected position to be 6, actual %zd", parcBuffer_Position(buffer)); + assertTrue(strcmp("App:1=", actual) == 0, "Expected %s, actual %s", expected, actual); + parcMemory_Deallocate((void **) &actual); + ccnxNameLabel_Release(&label); + parcBuffer_Release(&buffer); + + expected = "10:param=value"; + buffer = parcBuffer_WrapCString(expected); + label = ccnxNameLabel_Parse(buffer); + actual = ccnxNameLabel_ToString(label); + assertTrue(parcBuffer_Position(buffer) == 9, "Expected position to be 9, actual %zd", parcBuffer_Position(buffer)); + assertTrue(strcmp("10:param=", actual) == 0, "Expected %s, actual %s", "10:param=", actual); + parcMemory_Deallocate((void **) &actual); + ccnxNameLabel_Release(&label); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxNameType_Parse_DecimalParameterLabel) +{ + char *expected = "10:param=value"; + PARCBuffer *buffer = parcBuffer_WrapCString(expected); + CCNxNameLabel *label = ccnxNameLabel_Parse(buffer); + char *actual = ccnxNameLabel_ToString(label); + assertTrue(parcBuffer_Position(buffer) == 9, "Expected position to be 9, actual %zd", parcBuffer_Position(buffer)); + assertTrue(strcmp("10:param=", actual) == 0, "Expected %s, actual %s", "10:param=", actual); + parcMemory_Deallocate((void **) &actual); + ccnxNameLabel_Release(&label); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxNameType_Parse_HexadecimalParameterLabel) +{ + PARCBuffer *buffer = parcBuffer_WrapCString("0xaa:param=value"); + CCNxNameLabel *label = ccnxNameLabel_Parse(buffer); + char *actual = ccnxNameLabel_ToString(label); + assertTrue(parcBuffer_Position(buffer) == 11, "Expected position to be 11, actual %zd", parcBuffer_Position(buffer)); + char *expected = "170:param="; + assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual); + parcMemory_Deallocate((void **) &actual); + ccnxNameLabel_Release(&label); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxNameType_Parse_BadHexLabel) +{ + PARCBuffer *buffer = parcBuffer_WrapCString("0xgg:param=value"); + CCNxNameLabel *label = ccnxNameLabel_Parse(buffer); + assertFalse(ccnxNameLabel_IsValid(label), "Expected an invalid CCNxNameLabel from an invalid specification."); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxNameType_Parse_OutOfRangeLabel) +{ + PARCBuffer *buffer = parcBuffer_WrapCString("0x123456=value"); + CCNxNameLabel *label = ccnxNameLabel_Parse(buffer); + char *actual = ccnxNameLabel_ToString(label); + + assertTrue(parcBuffer_Position(buffer) == 9, "Expected position to be 9, actual %zd", parcBuffer_Position(buffer)); + char *expected = "1193046="; + assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual); + parcMemory_Deallocate((void **) &actual); + ccnxNameLabel_Release(&label); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxNameType_Parse_UknownMnemonicLabel) +{ + PARCBuffer *buffer = parcBuffer_WrapCString("abc=value"); + CCNxNameLabel *label = ccnxNameLabel_Parse(buffer); + + assertFalse(ccnxNameLabel_IsValid(label), "Expected an invalid CCNxNameLabel from an invalid specification."); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxNameType_Parse_KnownLabel) +{ + PARCBuffer *buffer = parcBuffer_WrapCString("Serial=value"); + CCNxNameLabel *label = ccnxNameLabel_Parse(buffer); + char *actual = ccnxNameLabel_ToString(label); + parcMemory_Deallocate((void **) &actual); + ccnxNameLabel_Release(&label); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxNameType_Parse_DefaultLabel) +{ + PARCBuffer *buffer = parcBuffer_WrapCString("value"); + CCNxNameLabel *label = ccnxNameLabel_Parse(buffer); + char *actual = ccnxNameLabel_ToString(label); + char *expected = "Name="; + assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual); + parcMemory_Deallocate((void **) &actual); + ccnxNameLabel_Release(&label); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxNameType_Parse_EmptyLabel) +{ + PARCBuffer *buffer = parcBuffer_WrapCString("=value"); + CCNxNameLabel *label = ccnxNameLabel_Parse(buffer); + assertNull(label, "Expected a NULL return value from ccnxNameLabel_Parse for the invalid string '=value'"); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_FIXTURE(Errors) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Errors) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Errors) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_NameType); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/test/test_ccnx_NameSegment.c b/libccnx-common/ccnx/common/test/test_ccnx_NameSegment.c new file mode 100644 index 00000000..b691c52a --- /dev/null +++ b/libccnx-common/ccnx/common/test/test_ccnx_NameSegment.c @@ -0,0 +1,739 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ +#include <config.h> +#include <stdio.h> +#include <LongBow/unit-test.h> + +#include <parc/algol/parc_Memory.h> +#include <parc/algol/parc_SafeMemory.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnx_NameSegment.c" + +LONGBOW_TEST_RUNNER(ccnx_NameComponent) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnx_NameComponent) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_NameComponent) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_CreateTypeValue); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_Copy); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_Copy_WithParameter); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_Length); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_GetType); + + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ParseURISegment); + + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ToString_META); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ToString_APP0); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ToString_NAME); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ToString_NAME_NotDefault); + + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ToString_SERIAL); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ParseURISegment_RawNAME); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ToString_APP256); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ToString_PAYLOADHASH); + + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ParseURISegment_NAME); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ParseURISegment_META); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ParseURISegment_list); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ParseURISegment_UnknownLabel); + + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_ZeroLength); + + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_Compare_Contract); + + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_Equals_Contract); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_HashCode); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_Display); + + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_IsValid); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_IsValid_NULL); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegment_IsValid_InnerNULL1); +} + +static uint32_t initialAllocationCount; + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + initialAllocationCount = parcMemory_Outstanding(); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t remainingAllocations = parcMemory_Outstanding() - initialAllocationCount; + if (remainingAllocations > 0) { + printf("%s leaks memory by %u allocations\n", longBowTestCase_GetName(testCase), remainingAllocations); + parcSafeMemory_ReportAllocation(STDOUT_FILENO); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_IsValid) +{ + PARCBuffer *value = parcBuffer_WrapCString("Test"); + CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, value); + + assertTrue(ccnxNameSegment_IsValid(segment), "Expected a valid CCNxNameSegment."); + + ccnxNameSegment_Release(&segment); + parcBuffer_Release(&value); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_IsValid_NULL) +{ + assertFalse(ccnxNameSegment_IsValid(NULL), "Expected NULL to be an invalid CCNxNameSegment."); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_IsValid_InnerNULL1) +{ + PARCBuffer *buf = parcBuffer_WrapCString("Test"); + CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buf); + + // Hit the NULL case + PARCBuffer *oldBuffer = segment->value; + segment->value = NULL; + + assertFalse(ccnxNameSegment_IsValid(segment), + "Expected a name segment with a NULL value to be invalid."); + + segment->value = oldBuffer; + + ccnxNameSegment_Release(&segment); + parcBuffer_Release(&buf); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_CreateTypeValue) +{ + PARCBuffer *buf = parcBuffer_WrapCString("Test"); + + CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buf); + assertNotNull(segment, "Expected non-null"); + + ccnxNameSegment_Release(&segment); + parcBuffer_Release(&buf); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_CreateTypeParameterValue) +{ + PARCBuffer *parameter = parcBuffer_WrapCString("param"); + PARCBuffer *value = parcBuffer_WrapCString("Value"); + + CCNxNameLabel *label = ccnxNameLabel_Create(CCNxNameLabelType_NAME, parameter); + CCNxNameSegment *segment = ccnxNameSegment_CreateLabelValue(label, value); + ccnxNameLabel_Release(&label); + assertNotNull(segment, "Expected non-null"); + + ccnxNameSegment_Release(&segment); + parcBuffer_Release(¶meter); + parcBuffer_Release(&value); +} + +// Convert the tests to use this table, instead of individual tests. +struct nameSegments { + char *lciSegment; + CCNxNameLabelType nameType; + char *parameter; + char *value; +} nameSegment[] = { + { .lciSegment = "NAME", + .nameType = CCNxNameLabelType_NAME, .parameter = NULL, .value = "NAME", }, + { .lciSegment = CCNxNameLabel_Name "=" "NAME", + .nameType = CCNxNameLabelType_NAME, .parameter = NULL, .value = "NAME", }, + { .lciSegment = CCNxNameLabel_Chunk "=" "Chunk", + .nameType = CCNxNameLabelType_CHUNK, .parameter = NULL, .value = "Chunk", }, + { .lciSegment = CCNxNameLabel_Chunk ":param=" "Chunk", + .nameType = CCNxNameLabelType_CHUNK, .parameter = "param", .value = "Chunk", }, + { .lciSegment = CCNxNameLabel_App ":100=" "app100", + .nameType = CCNxNameLabelType_App(100), .parameter = NULL, .value = "app100", }, + { .lciSegment = NULL }, +}; + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_ParseURISegment_list) +{ + for (struct nameSegments *p = &nameSegment[0]; p->lciSegment != NULL; p++) { + PARCURISegment *segment = parcURISegment_Parse(p->lciSegment, NULL); + + CCNxNameSegment *actual = ccnxNameSegment_ParseURISegment(segment); + + CCNxNameLabelType type = ccnxNameSegment_GetType(actual); + assertTrue(p->nameType == type, "Expected %04x, actual %04x", p->nameType, type); + + PARCBuffer *valueValue = parcBuffer_WrapCString(p->value); + PARCBuffer *expectedParam = p->parameter == NULL ? NULL : parcBuffer_WrapCString(p->parameter); + CCNxNameLabel *label = ccnxNameLabel_Create(p->nameType, expectedParam); + CCNxNameSegment *expected = ccnxNameSegment_CreateLabelValue(label, valueValue); + ccnxNameLabel_Release(&label); + + parcBuffer_Release(&valueValue); + if (expectedParam != NULL) { + parcBuffer_Release(&expectedParam); + } + + char *expectedString = ccnxNameSegment_ToString(expected); + char *actualString = ccnxNameSegment_ToString(actual); + assertTrue(ccnxNameSegment_Equals(expected, actual), + "Expected '%s' Actual, '%s", expectedString, actualString); + parcMemory_Deallocate((void **) &expectedString); + parcMemory_Deallocate((void **) &actualString); + + ccnxNameSegment_Release(&expected); + ccnxNameSegment_Release(&actual); + parcURISegment_Release(&segment); + } +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_ParseURISegment_RawNAME) +{ + char *lciSegment = "NAME"; + PARCURISegment *segment = parcURISegment_Parse(lciSegment, NULL); + + CCNxNameSegment *actual = ccnxNameSegment_ParseURISegment(segment); + + CCNxNameLabelType type = ccnxNameSegment_GetType(actual); + assertTrue(CCNxNameLabelType_NAME == type, "Expected %04x, actual %04x", CCNxNameLabelType_NAME, type); + + PARCBuffer *buf = parcBuffer_WrapCString("NAME"); + CCNxNameSegment *expected = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buf); + + assertTrue(ccnxNameSegment_Equals(expected, actual), "Error in ccnxNameSegment_ParseURISegment") + { + char *expectedString = ccnxNameSegment_ToString(expected); + char *actualString = ccnxNameSegment_ToString(expected); + fprintf(stderr, "Expected '%s', actual '%s'", expectedString, actualString); + parcMemory_Deallocate((void **) expectedString); + parcMemory_Deallocate((void **) actualString); + }; + + parcBuffer_Release(&buf); + ccnxNameSegment_Release(&expected); + ccnxNameSegment_Release(&actual); + parcURISegment_Release(&segment); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_ParseURISegment_NAME) +{ + char *lciSegment = CCNxNameLabel_Name "=" "NAME"; + PARCURISegment *segment = parcURISegment_Parse(lciSegment, NULL); + + CCNxNameSegment *actual = ccnxNameSegment_ParseURISegment(segment); + + CCNxNameLabelType type = ccnxNameSegment_GetType(actual); + assertTrue(CCNxNameLabelType_NAME == type, "Expected %04x, actual %04x", CCNxNameLabelType_NAME, type); + + PARCBuffer *buf = parcBuffer_WrapCString("NAME"); + CCNxNameSegment *expected = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buf); + + assertTrue(ccnxNameSegment_Equals(expected, actual), "Error in ccnxNameSegment_ParseURISegment") + { + char *expectedString = ccnxNameSegment_ToString(expected); + char *actualString = ccnxNameSegment_ToString(expected); + fprintf(stderr, "Expected '%s', actual '%s'", expectedString, actualString); + parcMemory_Deallocate((void **) expectedString); + parcMemory_Deallocate((void **) actualString); + }; + + ccnxNameSegment_Release(&expected); + ccnxNameSegment_Release(&actual); + parcURISegment_Release(&segment); + parcBuffer_Release(&buf); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_ParseURISegment_META) +{ + char *lciSegment = CCNxNameLabel_ChunkMeta "=" "META"; + PARCURISegment *segment = parcURISegment_Parse(lciSegment, NULL); + + CCNxNameSegment *actual = ccnxNameSegment_ParseURISegment(segment); + + CCNxNameLabelType type = ccnxNameSegment_GetType(actual); + assertTrue(CCNxNameLabelType_CHUNKMETA == type, "Expected 0x%04x, actual 0x%04x", CCNxNameLabelType_CHUNKMETA, type); + + PARCBuffer *buf = parcBuffer_WrapCString("META"); + + CCNxNameSegment *expected = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_CHUNKMETA, buf); + + assertTrue(ccnxNameSegment_Equals(expected, actual), "Error in ccnxNameSegment_ParseURISegment") + { + char *expectedString = ccnxNameSegment_ToString(expected); + char *actualString = ccnxNameSegment_ToString(expected); + fprintf(stderr, "Expected '%s', actual '%s'", expectedString, actualString); + parcMemory_Deallocate((void **) expectedString); + parcMemory_Deallocate((void **) actualString); + }; + + ccnxNameSegment_Release(&expected); + ccnxNameSegment_Release(&actual); + parcURISegment_Release(&segment); + parcBuffer_Release(&buf); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_ParseURISegment_UnknownLabel) +{ + char *lciSegment = "unknown:param" "=" "abcdef"; + PARCURISegment *segment = parcURISegment_Parse(lciSegment, NULL); + + CCNxNameSegment *actual = ccnxNameSegment_ParseURISegment(segment); + + parcURISegment_Release(&segment); + + assertNull(actual, "Expected NULL return from ccnxNameSegment_ParseURISegment"); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_ParseURISegment_APP0) +{ + char *lciSegment = CCNxNameLabelType_LabelApp(0) "=" "APP0"; + PARCURISegment *segment = parcURISegment_Parse(lciSegment, NULL); + + CCNxNameSegment *actual = ccnxNameSegment_ParseURISegment(segment); + + CCNxNameLabelType type = ccnxNameSegment_GetType(actual); + assertTrue(CCNxNameLabelType_App(0) == type, "Expected %04x, actual %04x", CCNxNameLabelType_App(0), type); + + PARCBuffer *buf = parcBuffer_WrapCString("APP0"); + + CCNxNameSegment *expected = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_App(0), buf); + assertTrue(ccnxNameSegment_Equals(expected, actual), "Error in ccnxNameSegment_ParseURISegment") + { + char *expectedString = ccnxNameSegment_ToString(expected); + char *actualString = ccnxNameSegment_ToString(expected); + fprintf(stderr, "Expected '%s', actual '%s'", expectedString, actualString); + parcMemory_Deallocate((void **) expectedString); + parcMemory_Deallocate((void **) actualString); + }; + + ccnxNameSegment_Release(&expected); + ccnxNameSegment_Release(&actual); + parcURISegment_Release(&segment); + parcBuffer_Release(&buf); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_ParseURISegment_APP256) +{ + char *lciSegment = CCNxNameLabelType_LabelApp(255) "=" "APP255"; + PARCURISegment *segment = parcURISegment_Parse(lciSegment, NULL); + + CCNxNameSegment *actual = ccnxNameSegment_ParseURISegment(segment); + + CCNxNameLabelType type = ccnxNameSegment_GetType(actual); + assertTrue(CCNxNameLabelType_App(255) == type, "Expected %04x, actual %04x", CCNxNameLabelType_App(255), type); + + PARCBuffer *buf = parcBuffer_WrapCString("APP255"); + CCNxNameSegment *expected = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_App(255), buf); + parcBuffer_Release(&buf); + + assertTrue(ccnxNameSegment_Equals(expected, actual), "Error in ccnxNameSegment_ParseURISegment") + { + char *expectedString = ccnxNameSegment_ToString(expected); + char *actualString = ccnxNameSegment_ToString(expected); + fprintf(stderr, "Expected '%s', actual '%s'", expectedString, actualString); + parcMemory_Deallocate((void **) expectedString); + parcMemory_Deallocate((void **) actualString); + }; + + ccnxNameSegment_Release(&expected); + ccnxNameSegment_Release(&actual); + parcURISegment_Release(&segment); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_ParseURISegment) +{ + char *lciSegment = CCNxNameLabel_Name "=" "abcde"; + PARCURISegment *segment = parcURISegment_Parse(lciSegment, NULL); + + CCNxNameSegment *actual = ccnxNameSegment_ParseURISegment(segment); + + CCNxNameLabelType type = ccnxNameSegment_GetType(actual); + assertTrue(CCNxNameLabelType_NAME == type, + "Expected %04x, actual %04x", 0x20, type); + + PARCBuffer *buf = parcBuffer_WrapCString("abcde"); + + CCNxNameSegment *expected = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buf); + + assertTrue(ccnxNameSegment_Equals(expected, actual), "Error in ccnxNameSegment_ParseURISegment") + { + char *expectedString = ccnxNameSegment_ToString(expected); + char *actualString = ccnxNameSegment_ToString(expected); + fprintf(stderr, "Expected '%s', actual '%s'", expectedString, actualString); + parcMemory_Deallocate((void **) expectedString); + parcMemory_Deallocate((void **) actualString); + }; + + ccnxNameSegment_Release(&expected); + parcBuffer_Release(&buf); + ccnxNameSegment_Release(&actual); + parcURISegment_Release(&segment); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_ZeroLength) +{ + char *begin = ""; + + PARCBuffer *buffer = parcBuffer_WrapCString(begin); + CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buffer); + + assertNotNull(segment, "Expected non-null"); + assertTrue(ccnxNameSegment_Length(segment) == 0, "Failed to create a zero length segment"); + + ccnxNameSegment_Release(&segment); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_Equals_Contract) +{ + PARCBuffer *bufX = parcBuffer_WrapCString("Test"); + PARCBuffer *bufY = parcBuffer_WrapCString("Test"); + PARCBuffer *bufZ = parcBuffer_WrapCString("Test"); + PARCBuffer *bufU1 = parcBuffer_WrapCString("Test"); + PARCBuffer *bufU2 = parcBuffer_WrapCString("blah"); + + CCNxNameSegment *x = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufX); + CCNxNameSegment *y = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufY); + CCNxNameSegment *z = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufZ); + CCNxNameSegment *u1 = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_CHUNKMETA, bufU1); + CCNxNameSegment *u2 = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufU2); + + assertEqualsContract(ccnxNameSegment_Equals, x, y, z, u1, u2, NULL); + + ccnxNameSegment_Release(&x); + ccnxNameSegment_Release(&y); + ccnxNameSegment_Release(&z); + ccnxNameSegment_Release(&u1); + ccnxNameSegment_Release(&u2); + + parcBuffer_Release(&bufX); + parcBuffer_Release(&bufY); + parcBuffer_Release(&bufZ); + parcBuffer_Release(&bufU1); + parcBuffer_Release(&bufU2); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_Compare_Contract) +{ + char *aString = "foo"; + PARCBuffer *bufA = parcBuffer_WrapCString(aString); + CCNxNameSegment *a = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufA); + + PARCBuffer *bufFoo = parcBuffer_WrapCString("foo"); + PARCBuffer *bufFon = parcBuffer_WrapCString("fon"); + PARCBuffer *bufFo = parcBuffer_WrapCString("fo"); + PARCBuffer *bufFop = parcBuffer_WrapCString("fop"); + PARCBuffer *bufFooa = parcBuffer_WrapCString("fooa"); + + CCNxNameSegment **equivalents = (CCNxNameSegment *[]) { + ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufFoo), + NULL + }; + CCNxNameSegment **lessers = (CCNxNameSegment *[]) { + ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufFon), + ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufFo), + NULL + }; + CCNxNameSegment **greaters = (CCNxNameSegment *[]) { + ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufFop), + ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufFooa), + NULL + }; + + assertCompareToContract(ccnxNameSegment_Compare, a, equivalents, lessers, greaters); + + ccnxNameSegment_Release(&a); + + for (int i = 0; equivalents[i] != NULL; i++) { + ccnxNameSegment_Release(&equivalents[i]); + } + for (int i = 0; lessers[i] != NULL; i++) { + ccnxNameSegment_Release(&lessers[i]); + } + for (int i = 0; greaters[i] != NULL; i++) { + ccnxNameSegment_Release(&greaters[i]); + } + + parcBuffer_Release(&bufFoo); + parcBuffer_Release(&bufFon); + parcBuffer_Release(&bufFo); + parcBuffer_Release(&bufFop); + parcBuffer_Release(&bufFooa); + parcBuffer_Release(&bufA); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_Length) +{ + char *expected = "foo"; + + PARCBuffer *buffer = parcBuffer_WrapCString(expected); + CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buffer); + + size_t actual = ccnxNameSegment_Length(segment); + + ccnxNameSegment_Release(&segment); + + assertTrue(strlen(expected) == actual, + "Expected %zd, actual %zd", strlen(expected), actual); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_Copy) +{ + PARCBuffer *buf = parcBuffer_WrapCString("foo"); + CCNxNameSegment *expected = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buf); + CCNxNameSegment *actual = ccnxNameSegment_Copy(expected); + CCNxNameSegment *acquiredCopy = ccnxNameSegment_Acquire(expected); + + assertTrue(expected != actual, "Expected a distinct copy of the original."); + + char *expectedString = ccnxNameSegment_ToString(expected); + char *actualString = ccnxNameSegment_ToString(actual); + char *acquiredString = ccnxNameSegment_ToString(acquiredCopy); + assertTrue(ccnxNameSegment_Equals(expected, actual), "Expected %s, actual %s", expectedString, actualString); + assertTrue(ccnxNameSegment_Equals(expected, acquiredCopy), "Expected %s, actual %s", expectedString, acquiredString); + + parcMemory_Deallocate((void **) &expectedString); + parcMemory_Deallocate((void **) &actualString); + parcMemory_Deallocate((void **) &acquiredString); + + ccnxNameSegment_Release(&acquiredCopy); + ccnxNameSegment_Release(&expected); + ccnxNameSegment_Release(&actual); + parcBuffer_Release(&buf); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_Copy_WithParameter) +{ + PARCBuffer *value = parcBuffer_WrapCString("value"); + PARCBuffer *parameter = parcBuffer_WrapCString("param"); + CCNxNameLabel *label = ccnxNameLabel_Create(CCNxNameLabelType_NAME, parameter); + CCNxNameSegment *expected = ccnxNameSegment_CreateLabelValue(label, value); + ccnxNameLabel_Release(&label); + parcBuffer_Release(&value); + parcBuffer_Release(¶meter); + + CCNxNameSegment *actual = ccnxNameSegment_Copy(expected); + + assertTrue(expected != actual, "Expected a distinct copy of the original."); + + char *expectedString = ccnxNameSegment_ToString(expected); + char *actualString = ccnxNameSegment_ToString(actual); + assertTrue(ccnxNameSegment_Equals(expected, actual), "Expected '%s', actual '%s'", expectedString, actualString); + + parcMemory_Deallocate((void **) &expectedString); + parcMemory_Deallocate((void **) &actualString); + + ccnxNameSegment_Release(&expected); + ccnxNameSegment_Release(&actual); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_GetType) +{ + PARCBuffer *buf = parcBuffer_WrapCString("hello"); + CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buf); + + assertTrue(CCNxNameLabelType_NAME == ccnxNameSegment_GetType(segment), + "Expected type %d, actual %d", CCNxNameLabelType_NAME, ccnxNameSegment_GetType(segment)); + + ccnxNameSegment_Release(&segment); + parcBuffer_Release(&buf); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_ToString_META) +{ + char *expected = CCNxNameLabel_ChunkMeta "=META"; + PARCBuffer *buf = parcBuffer_WrapCString("META"); + CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_CHUNKMETA, buf); + char *actual = ccnxNameSegment_ToString(segment); + assertTrue(strcmp(expected, actual) == 0, + "Expected %s, actual %s", expected, actual); + parcMemory_Deallocate((void **) &actual); + + ccnxNameSegment_Release(&segment); + parcBuffer_Release(&buf); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_ToString_PAYLOADHASH) +{ + char *expected = CCNxNameLabel_InterestPayloadId "=PAYLOADHASH"; + PARCBuffer *buf = parcBuffer_WrapCString("PAYLOADHASH"); + CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_PAYLOADID, buf); + + char *actual = ccnxNameSegment_ToString(segment); + assertTrue(strcmp(expected, actual) == 0, + "Expected %s, actual %s", expected, actual); + parcMemory_Deallocate((void **) &actual); + + ccnxNameSegment_Release(&segment); + parcBuffer_Release(&buf); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_ToString_NAME) +{ + PARCBuffer *buf = parcBuffer_WrapCString("NAME"); + CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buf); + + // Note that this is different than the other tests for segments because a NAME name segment + // is the default type and as such the string representation doesn't include the leading label specification. + char *expected = "NAME"; + char *actual = ccnxNameSegment_ToString(segment); + assertTrue(strcmp(expected, actual) == 0, + "Expected %s, actual %s", expected, actual); + parcMemory_Deallocate((void **) &actual); + + ccnxNameSegment_Release(&segment); + parcBuffer_Release(&buf); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_ToString_NAME_NotDefault) +{ + PARCBuffer *value = parcBuffer_WrapCString("MiISAg=="); + CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, value); + + // Note that this is different than the other tests for segments because a NAME name segment + // is the default type and as such the string representation doesn't include the leading label specification. + char *expected = CCNxNameLabel_Name "=" "MiISAg%3D%3D"; + char *actual = ccnxNameSegment_ToString(segment); + assertTrue(strcmp(expected, actual) == 0, + "Expected %s, actual %s", expected, actual); + parcMemory_Deallocate((void **) &actual); + + ccnxNameSegment_Release(&segment); + parcBuffer_Release(&value); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_ToString_APP0) +{ + char *expected = CCNxNameLabelType_LabelApp(0) "=APP0"; + PARCBuffer *buf = parcBuffer_WrapCString("APP0"); + CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_App(0), buf); + + char *actual = ccnxNameSegment_ToString(segment); + assertTrue(strcmp(expected, actual) == 0, + "Expected %s, actual %s", expected, actual); + parcMemory_Deallocate((void **) &actual); + + ccnxNameSegment_Release(&segment); + parcBuffer_Release(&buf); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_ToString_SERIAL) +{ + char *expected = CCNxNameLabel_Serial "=serialnumber"; + PARCBuffer *buf = parcBuffer_WrapCString("serialnumber"); + CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_SERIAL, buf); + + char *actual = ccnxNameSegment_ToString(segment); + assertTrue(strcmp(expected, actual) == 0, + "Expected %s, actual %s", expected, actual); + parcMemory_Deallocate((void **) &actual); + + ccnxNameSegment_Release(&segment); + parcBuffer_Release(&buf); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_ToString_APP256) +{ + char *expected = CCNxNameLabelType_LabelApp(255) "=APP255"; + PARCBuffer *buf = parcBuffer_WrapCString("APP255"); + + CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_App(255), buf); + char *actual = ccnxNameSegment_ToString(segment); + assertTrue(strcmp(expected, actual) == 0, + "Expected %s, actual %s", expected, actual); + parcMemory_Deallocate((void **) &actual); + + ccnxNameSegment_Release(&segment); + parcBuffer_Release(&buf); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_HashCode) +{ + PARCBuffer *bufA = parcBuffer_WrapCString("Test"); + + CCNxNameSegment *segmentA = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufA); + CCNxNameSegment *segmentB = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_CHUNKMETA, bufA); + + assertFalse(ccnxNameSegment_HashCode(segmentA) == ccnxNameSegment_HashCode(segmentB), + "Expected different hash codes"); + + PARCBuffer *bufC = parcBuffer_WrapCString("Not Test"); + + CCNxNameSegment *segmentC = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufC); + + assertFalse(ccnxNameSegment_HashCode(segmentA) == ccnxNameSegment_HashCode(segmentC), + "Expected different hash codes"); + + CCNxNameSegment *segmentD = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, bufA); + + assertTrue(ccnxNameSegment_HashCode(segmentD) == ccnxNameSegment_HashCode(segmentA), + "Expected same hash codes"); + + ccnxNameSegment_Release(&segmentA); + ccnxNameSegment_Release(&segmentB); + ccnxNameSegment_Release(&segmentC); + ccnxNameSegment_Release(&segmentD); + + parcBuffer_Release(&bufA); + parcBuffer_Release(&bufC); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegment_Display) +{ + PARCBuffer *buf = parcBuffer_WrapCString("Test"); + + CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buf); + + ccnxNameSegment_Display(segment, 0); + + ccnxNameSegment_Release(&segment); + parcBuffer_Release(&buf); +} + +LONGBOW_TEST_CASE_EXPECTS(Global, ccnxNameSegment_AssertValid_Invalid, .event = &LongBowAssertEvent) +{ + ccnxNameSegment_AssertValid(NULL); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_NameComponent); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/test/test_ccnx_NameSegmentNumber.c b/libccnx-common/ccnx/common/test/test_ccnx_NameSegmentNumber.c new file mode 100755 index 00000000..fb14ef39 --- /dev/null +++ b/libccnx-common/ccnx/common/test/test_ccnx_NameSegmentNumber.c @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ +#include "../ccnx_NameSegmentNumber.c" + +#include <LongBow/unit-test.h> + +#include <stdio.h> +#include <inttypes.h> + +#include <parc/algol/parc_SafeMemory.h> + +LONGBOW_TEST_RUNNER(test_ccnx_NameSegmentNumber) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(test_ccnx_NameSegmentNumber) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(test_ccnx_NameSegmentNumber) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegmentNumber_Create64bits); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegmentNumber_Create56bits); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegmentNumber_Create48bits); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegmentNumber_Create40bits); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegmentNumber_Create32bits); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegmentNumber_Create24bits); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegmentNumber_Create16bits); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegmentNumber_Create8bits); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegmentNumber_BorderCases); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegmentNumber_IsValid); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegmentNumber_IsValid_False); + LONGBOW_RUN_TEST_CASE(Global, ccnxNameSegmentNumber_AssertValid); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegmentNumber_Create64bits) +{ + uint64_t expected = 0x123456789ABCDEF0; + CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected); + + uint64_t actual = ccnxNameSegmentNumber_Value(segment); + + assertTrue(expected == actual, "Expected 0x%" PRIX64 " actual 0x%" PRIX64 "", expected, actual); + + ccnxNameSegment_Release(&segment); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegmentNumber_Create56bits) +{ + uint64_t expected = 0x123456789ABCDE; + CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected); + + uint64_t actual = ccnxNameSegmentNumber_Value(segment); + + assertTrue(expected == actual, "Expected 0x%" PRIX64 " actual 0x%" PRIX64 "", expected, actual); + ccnxNameSegment_Release(&segment); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegmentNumber_Create48bits) +{ + uint64_t expected = 0x123456789ABC; + CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected); + + uint64_t actual = ccnxNameSegmentNumber_Value(segment); + + assertTrue(expected == actual, "Expected 0x%" PRIX64 " actual 0x%" PRIX64 "", expected, actual); + ccnxNameSegment_Release(&segment); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegmentNumber_Create40bits) +{ + uint64_t expected = 0x123456789A; + CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected); + + uint64_t actual = ccnxNameSegmentNumber_Value(segment); + + assertTrue(expected == actual, "Expected 0x%" PRIX64 " actual 0x%" PRIX64 "", expected, actual); + ccnxNameSegment_Release(&segment); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegmentNumber_Create32bits) +{ + uint64_t expected = 0x12345678; + CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected); + + uint64_t actual = ccnxNameSegmentNumber_Value(segment); + + assertTrue(expected == actual, "Expected 0x%" PRIX64 " actual 0x%" PRIX64 "", expected, actual); + ccnxNameSegment_Release(&segment); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegmentNumber_Create24bits) +{ + uint64_t expected = 0x123456; + CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected); + + uint64_t actual = ccnxNameSegmentNumber_Value(segment); + + assertTrue(expected == actual, "Expected 0x%" PRIX64 " actual 0x%" PRIX64 "", expected, actual); + ccnxNameSegment_Release(&segment); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegmentNumber_Create16bits) +{ + uint64_t expected = 0x1234; + CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected); + + uint64_t actual = ccnxNameSegmentNumber_Value(segment); + + assertTrue(expected == actual, "Expected 0x%" PRIX64 " actual 0x%" PRIX64 "", expected, actual); + ccnxNameSegment_Release(&segment); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegmentNumber_Create8bits) +{ + uint64_t expected = 0x12; + CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected); + + uint64_t actual = ccnxNameSegmentNumber_Value(segment); + + assertTrue(expected == actual, "Expected 0x%" PRIX64 " actual 0x%" PRIX64 "", expected, actual); + ccnxNameSegment_Release(&segment); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegmentNumber_BorderCases) +{ + struct test_struct { + uint64_t value; + size_t length; + uint8_t *encoded; + } test_vector[] = { + { .value = 0x0000000000000000ULL, .length = 1, .encoded = (uint8_t[1]) { 0x00 } }, + { .value = 0x0000000000000001ULL, .length = 1, .encoded = (uint8_t[1]) { 0x01 } }, + { .value = 0x00000000000000FFULL, .length = 1, .encoded = (uint8_t[1]) { 0xFF } }, + { .value = 0x0000000000000100ULL, .length = 2, .encoded = (uint8_t[2]) { 0x01, 0x00} }, + { .value = 0x0100000000000100ULL, .length = 8, .encoded = (uint8_t[8]) { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00} }, + { .value = 0x8000000000000100ULL, .length = 8, .encoded = (uint8_t[8]) { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00} }, + { .value = 0xFFFFFFFFFFFFFFFFULL, .length = 8, .encoded = (uint8_t[8]) { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} }, + { .value = 0, .length = 0, .encoded = NULL } + }; + + for (int i = 0; test_vector[i].encoded != NULL; i++) { + PARCBuffer *buffer = + parcBuffer_Wrap(test_vector[i].encoded, test_vector[i].length, 0, test_vector[i].length); + CCNxNameSegment *expected = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buffer); + + CCNxNameSegment *actual = ccnxNameSegmentNumber_Create(CCNxNameLabelType_NAME, test_vector[i].value); + + assertTrue(ccnxNameSegment_Equals(expected, actual), + "Buffers do not match: test_vector[%d] value %" PRIX64 " Expected %" PRIX64 " actual %" PRIX64 "", + i, + test_vector[i].value, + ccnxNameSegmentNumber_Value(expected), + ccnxNameSegmentNumber_Value(actual)); + + ccnxNameSegment_Release(&expected); + ccnxNameSegment_Release(&actual); + parcBuffer_Release(&buffer); + } +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegmentNumber_AssertValid) +{ + uint64_t expected = 0x12; + CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected); + + ccnxNameSegmentNumber_AssertValid(segment); + ccnxNameSegment_Release(&segment); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegmentNumber_IsValid) +{ + uint64_t expected = 0x12; + CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected); + + assertTrue(ccnxNameSegmentNumber_IsValid(segment), "Expected the CCNxNameSegment to be valid."); + ccnxNameSegment_Release(&segment); +} + +LONGBOW_TEST_CASE(Global, ccnxNameSegmentNumber_IsValid_False) +{ + uint64_t expected = 0x12; + CCNxNameSegment *segment = ccnxNameSegmentNumber_Create(CCNxNameLabelType_CHUNK, expected); + + PARCBuffer *value = ccnxNameSegment_GetValue(segment); + parcBuffer_SetPosition(value, parcBuffer_Limit(value)); // Wreck the buffer by making it zero length. + + assertFalse(ccnxNameSegmentNumber_IsValid(segment), "Expected the CCNxNameSegment to be valid."); + ccnxNameSegment_Release(&segment); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_ccnx_NameSegmentNumber); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/test/test_ccnx_TimeStamp.c b/libccnx-common/ccnx/common/test/test_ccnx_TimeStamp.c new file mode 100755 index 00000000..d65ebd64 --- /dev/null +++ b/libccnx-common/ccnx/common/test/test_ccnx_TimeStamp.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ +#include <ccnx/common/ccnx_TimeStamp.c> + +#include <inttypes.h> +#include <time.h> + +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + + +LONGBOW_TEST_RUNNER(ccnx_TimeStamp) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +LONGBOW_TEST_RUNNER_SETUP(ccnx_TimeStamp) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_TimeStamp) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxTimeStamp_CreateFromCurrentUTCTime); + LONGBOW_RUN_TEST_CASE(Global, ccnxTimeStamp_CreateFromTimespec); + LONGBOW_RUN_TEST_CASE(Global, ccnxTimeStamp_CreateFromMillisecondsSinceEpoch); + LONGBOW_RUN_TEST_CASE(Global, ccnxTimeStamp_Copy); + LONGBOW_RUN_TEST_CASE(Global, ccnxTimeStamp_Equals); + + LONGBOW_RUN_TEST_CASE(Global, ccnxTimeStamp_AsNanoSeconds); + LONGBOW_RUN_TEST_CASE(Global, ccnxTimeStamp_CreateFromNanosecondsSinceEpoch); + LONGBOW_RUN_TEST_CASE(Global, ccnxTimeStamp_ToString); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxTimeStamp_CreateFromCurrentUTCTime) +{ + CCNxTimeStamp *timeStamp = ccnxTimeStamp_CreateFromCurrentUTCTime(); + assertNotNull(timeStamp, "Expected a non-null response"); + + ccnxTimeStamp_Release(&timeStamp); + assertNull(timeStamp, "Release failed to NULL the pointer."); +} + +LONGBOW_TEST_CASE(Global, ccnxTimeStamp_CreateFromTimespec) +{ + struct timespec time = { .tv_sec = 1, .tv_nsec = 1 }; + + CCNxTimeStamp *timeStamp = ccnxTimeStamp_CreateFromTimespec(&time); + assertNotNull(timeStamp, "Expected a non-null response"); + + struct timespec actualTime = ccnxTimeStamp_AsTimespec(timeStamp); + + assertTrue(time.tv_sec == actualTime.tv_sec && time.tv_nsec == actualTime.tv_nsec, "Expected timespec to be equal."); + + ccnxTimeStamp_Release(&timeStamp); + assertNull(timeStamp, "Release failed to NULL the pointer."); +} + +LONGBOW_TEST_CASE(Global, ccnxTimeStamp_CreateFromMillisecondsSinceEpoch) +{ + time_t theTimeInSeconds; + time(&theTimeInSeconds); + + CCNxTimeStamp *timeStamp = ccnxTimeStamp_CreateFromMillisecondsSinceEpoch((uint64_t) theTimeInSeconds * 1000); + assertNotNull(timeStamp, "Expected a non-null response"); + + struct timespec timeSpec = ccnxTimeStamp_AsTimespec(timeStamp); + + assertTrue(theTimeInSeconds == timeSpec.tv_sec, "Expected %ld, actual %ld", theTimeInSeconds, timeSpec.tv_sec); + + assertTrue(0 == timeSpec.tv_nsec, "Expected %d, actual %ld", 0, timeSpec.tv_nsec); + + ccnxTimeStamp_Release(&timeStamp); + assertNull(timeStamp, "Release failed to NULL the pointer."); +} + +LONGBOW_TEST_CASE(Global, ccnxTimeStamp_CreateFromNanosecondsSinceEpoch) +{ + uint64_t expected = 1099511627776ULL; + + CCNxTimeStamp *timeStamp = ccnxTimeStamp_CreateFromNanosecondsSinceEpoch(expected); + + uint64_t actual = ccnxTimeStamp_AsNanoSeconds(timeStamp); + + assertTrue(expected == actual, "Expected %" PRIu64 " actual %" PRIu64, expected, actual); + + ccnxTimeStamp_Release(&timeStamp); +} + +LONGBOW_TEST_CASE(Global, ccnxTimeStamp_Equals) +{ + time_t theTimeInSeconds; + time(&theTimeInSeconds); + + CCNxTimeStamp *x = ccnxTimeStamp_CreateFromMillisecondsSinceEpoch(theTimeInSeconds * 1000); + CCNxTimeStamp *y = ccnxTimeStamp_CreateFromMillisecondsSinceEpoch(theTimeInSeconds * 1000); + CCNxTimeStamp *z = ccnxTimeStamp_CreateFromMillisecondsSinceEpoch(theTimeInSeconds * 1000); + CCNxTimeStamp *u1 = ccnxTimeStamp_CreateFromMillisecondsSinceEpoch((theTimeInSeconds + 1) * 1000); + CCNxTimeStamp *u2 = ccnxTimeStamp_CreateFromMillisecondsSinceEpoch((theTimeInSeconds + 2) * 1000); + + assertEqualsContract(ccnxTimeStamp_Equals, x, y, z, u1, u2) + + ccnxTimeStamp_Release(&x); + ccnxTimeStamp_Release(&y); + ccnxTimeStamp_Release(&z); + ccnxTimeStamp_Release(&u1); + ccnxTimeStamp_Release(&u2); +} + +LONGBOW_TEST_CASE(Global, ccnxTimeStamp_Copy) +{ + time_t theTime; + time(&theTime); + + CCNxTimeStamp *timeStamp = ccnxTimeStamp_CreateFromMillisecondsSinceEpoch(theTime); + assertNotNull(timeStamp, "Expected a non-null response"); + + CCNxTimeStamp *copy = ccnxTimeStamp_Copy(timeStamp); + + char *expected = ccnxTimeStamp_ToString(timeStamp); + char *actual = ccnxTimeStamp_ToString(copy); + assertTrue(ccnxTimeStamp_Equals(timeStamp, copy), + "Expected %s actual %s.", expected, actual); + parcMemory_Deallocate((void **) &expected); + parcMemory_Deallocate((void **) &actual); + + ccnxTimeStamp_Release(&timeStamp); + ccnxTimeStamp_Release(©); + assertNull(timeStamp, "Destroy failed to NULL the pointer."); +} + +LONGBOW_TEST_CASE(Global, ccnxTimeStamp_AsNanoSeconds) +{ + uint64_t expected = 1099501627776ULL; + + CCNxTimeStamp *timeStamp = ccnxTimeStamp_CreateFromNanosecondsSinceEpoch(expected); + + uint64_t actual = ccnxTimeStamp_AsNanoSeconds(timeStamp); + + assertTrue(expected == actual, "Expected %" PRIu64 " actual %" PRIu64, expected, actual); + + ccnxTimeStamp_Release(&timeStamp); +} + +LONGBOW_TEST_CASE(Global, ccnxTimeStamp_ToString) +{ + CCNxTimeStamp *timeStamp = ccnxTimeStamp_CreateFromCurrentUTCTime(); + assertNotNull(timeStamp, "Expected a non-null response"); + + char *string = ccnxTimeStamp_ToString(timeStamp); + assertNotNull(string, "Expected non-null result."); + + parcMemory_Deallocate((void **) &string); + + ccnxTimeStamp_Release(&timeStamp); + assertNull(timeStamp, "Destroy failed to NULL the pointer."); + // See case 1016 + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_TimeStamp); + exit(longBowMain(argc, argv, testRunner, NULL)); +} diff --git a/libccnx-common/ccnx/common/test/test_ccnx_WireFormatMessage.c b/libccnx-common/ccnx/common/test/test_ccnx_WireFormatMessage.c new file mode 100755 index 00000000..43b27dc2 --- /dev/null +++ b/libccnx-common/ccnx/common/test/test_ccnx_WireFormatMessage.c @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Runner. +#include "../ccnx_WireFormatMessage.c" + +#include <stdio.h> + +#include <LongBow/unit-test.h> + +#include <parc/algol/parc_SafeMemory.h> + +#include <ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h> + +#include <ccnx/common/codec/ccnxCodec_TlvPacket.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_interest_nameA.h> +#include <ccnx/common/ccnx_ContentObject.h> + + +LONGBOW_TEST_RUNNER(ccnx_WireFormatMessage) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Static); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnx_WireFormatMessage) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_WireFormatMessage) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_AcquireRelease); + LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_AssertValid); + LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_Create); + LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_FromContentObjectPacketType); + LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_FromControlPacketType); + LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_FromInterestPacketType); + LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_FromInterestPacketTypeIoVec); + LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_GetDictionary); + LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_PutGetIoVec); + LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_GetWireFormatBuffer); + // + LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_CreateContentObjectHash); + LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_HashProtectedRegion); + // + LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_PutWireFormatBuffer); + LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_SetProtectedRegionLength); + LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_SetProtectedRegionStart); + LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_WriteToFile); + LONGBOW_RUN_TEST_CASE(Global, ccnxWireFormatMessage_SetHopLimit); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_AcquireRelease) +{ + PARCBuffer *buffer = parcBuffer_Allocate(10); + CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromInterestPacketType(CCNxTlvDictionary_SchemaVersion_V1, buffer); + + CCNxWireFormatMessage *ref = ccnxWireFormatMessage_Acquire(message); + assertNotNull(ref, "Expected a non-NULL reference to be acquired"); + + ccnxWireFormatMessage_Release(&message); + assertNotNull(ref, "Expected a non-NULL reference to be acquired"); + assertNull(message, "Expeced original message to be NULL"); + + ccnxWireFormatMessage_Release(&ref); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_AssertValid) +{ + PARCBuffer *wireFormat = parcBuffer_Wrap(v1_interest_nameA, sizeof(v1_interest_nameA), 0, sizeof(v1_interest_nameA)); + + CCNxWireFormatMessage *message = ccnxWireFormatMessage_Create(wireFormat); + assertNotNull(message, "Got null CCNxWireFormatMessage, after attempting to create with buffer"); + + ccnxWireFormatMessage_AssertValid(message); + + ccnxWireFormatMessage_Release(&message); + parcBuffer_Release(&wireFormat); +} + +LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_FromContentObjectPacketType) +{ + PARCBuffer *buffer = parcBuffer_Allocate(10); + CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromContentObjectPacketType(CCNxTlvDictionary_SchemaVersion_V1, buffer); + + assertTrue(ccnxTlvDictionary_IsContentObject((CCNxTlvDictionary *) message), "Wrong message type"); + + ccnxWireFormatMessage_Release(&message); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_FromControlPacketType) +{ + PARCBuffer *buffer = parcBuffer_Allocate(10); + CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromControlPacketType(CCNxTlvDictionary_SchemaVersion_V1, buffer); + + assertTrue(ccnxTlvDictionary_IsControl((CCNxTlvDictionary *) message), "Wrong message type"); + + ccnxWireFormatMessage_Release(&message); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_FromInterestPacketType) +{ + PARCBuffer *buffer = parcBuffer_Allocate(10); + CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromInterestPacketType(CCNxTlvDictionary_SchemaVersion_V1, buffer); + + assertTrue(ccnxTlvDictionary_IsInterest((CCNxTlvDictionary *) message), "Wrong message type"); + + ccnxWireFormatMessage_Release(&message); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_Create) +{ + PARCBuffer *wireFormat = parcBuffer_Wrap(v1_interest_nameA, sizeof(v1_interest_nameA), 0, sizeof(v1_interest_nameA)); + + CCNxWireFormatMessage *message = ccnxWireFormatMessage_Create(wireFormat); + assertNotNull(message, "Got null CCNxWireFormatMessage, after attempting to create with buffer"); + + ccnxWireFormatMessage_Release(&message); + parcBuffer_Release(&wireFormat); +} + +/*** + *** allocator(), deallocator(), createNetworkBufferIoVec() taken from test_ccnx_WireFormatFacadeV1.c + ***/ + +/* + * Small size allocator for creating a network buffer + */ +static size_t +_allocator(void *userarg, size_t bytes, void **output) +{ + const size_t allocationSize = *(size_t *) userarg; + void *allocated = parcMemory_Allocate(allocationSize); + *output = allocated; + return allocationSize; +} + +/* + * deallocator for network buffer + */ +static void +_deallocator(void *userarg, void **memoryPtr) +{ + parcMemory_Deallocate(memoryPtr); +} +static const CCNxCodecNetworkBufferMemoryBlockFunctions memory = { .allocator = _allocator, .deallocator = _deallocator }; + +/* + * Create a network buffer that looks like this. The actual number of iovecs might + * be a little different, but the digest area will span several iovec. + * + * +-----------+-----------+-----------+-----------+-----------+ + * iov[0] iov[1] iov[2] iov[3] + * +-----------+-----------+-----------+-----------+-----------+ + * ^ ^ + * | | + * start end + */ +static CCNxCodecNetworkBufferIoVec * +_createNetworkBufferIoVec(size_t allocationSize, size_t padlen, uint8_t pad[padlen], size_t datalen, uint8_t data[datalen]) +{ + CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&memory, &allocationSize); + // build the network buffer + ccnxCodecNetworkBuffer_PutArray(netbuff, padlen, pad); + ccnxCodecNetworkBuffer_PutArray(netbuff, datalen, data); + ccnxCodecNetworkBuffer_PutArray(netbuff, padlen, pad); + + CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff); + ccnxCodecNetworkBuffer_Release(&netbuff); + return vec; +} + +LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_FromInterestPacketTypeIoVec) +{ + uint8_t data[64]; + + uint8_t pad[32]; + CCNxCodecNetworkBufferIoVec *vec = _createNetworkBufferIoVec(512, 32, pad, 64, data); + + CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromInterestPacketTypeIoVec(CCNxTlvDictionary_SchemaVersion_V1, vec); + + assertNotNull(message, "Got null CCNxWireFormatMessage"); + assertTrue(ccnxTlvDictionary_IsInterest(message), "Wrong message type"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(message) == CCNxTlvDictionary_SchemaVersion_V1, + "Wrong schema, got %d expected %d", + ccnxTlvDictionary_GetSchemaVersion(message), CCNxTlvDictionary_SchemaVersion_V1); + + ccnxWireFormatMessage_Release(&message); + ccnxCodecNetworkBufferIoVec_Release(&vec); +} + +LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_GetDictionary) +{ + PARCBuffer *buffer = parcBuffer_Allocate(10); + CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromInterestPacketType(CCNxTlvDictionary_SchemaVersion_V1, buffer); + + CCNxTlvDictionary *dictionary = ccnxWireFormatMessage_GetDictionary(message); + assertNotNull(dictionary, "Expected to retrieve the dictionary from the CCNxWireFormatMessage"); + assertTrue(ccnxTlvDictionary_IsInterest(dictionary), "Wrong message type"); + + ccnxWireFormatMessage_Release(&message); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_PutGetIoVec) +{ + uint8_t *data = parcMemory_Allocate(64); + memset(data, 0, 64); + + PARCBuffer *buffer = parcBuffer_Allocate(1); + CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, 64, data); + CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff); + + CCNxTlvDictionary *packet = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + ccnxWireFormatMessage_PutIoVec((CCNxWireFormatMessage *) packet, iovec); + + CCNxCodecNetworkBufferIoVec *test = ccnxWireFormatMessage_GetIoVec((CCNxWireFormatMessage *) packet); + assertTrue(test == iovec, "Failed to get iovec from dictionary, expected %p got %p", (void *) iovec, (void *) test); + + ccnxTlvDictionary_Release(&packet); + parcBuffer_Release(&buffer); + ccnxCodecNetworkBufferIoVec_Release(&iovec); + ccnxCodecNetworkBuffer_Release(&netbuff); +} + +LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_GetWireFormatBuffer) +{ + PARCBuffer *buffer = parcBuffer_Allocate(1); + CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromInterestPacketType(CCNxTlvDictionary_SchemaVersion_V1, buffer); + + PARCBuffer *test = ccnxWireFormatMessage_GetWireFormatBuffer(message); + assertTrue(test == buffer, "Retrieved unexpected buffer: got %p expected %p", (void *) test, (void *) buffer); + + ccnxWireFormatMessage_Release(&message); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_PutWireFormatBuffer) +{ + PARCBuffer *buffer = parcBuffer_Allocate(1); + CCNxTlvDictionary *packet = ccnxTlvDictionary_Create(20, 20); + ccnxTlvDictionary_SetMessageType_Interest(packet, CCNxTlvDictionary_SchemaVersion_V1); + bool success = ccnxWireFormatMessage_PutWireFormatBuffer(packet, buffer); + + assertTrue(success, "Failed to put buffer in to dictionary"); + + PARCBuffer *test = ccnxWireFormatMessage_GetWireFormatBuffer(packet); + assertTrue(test == buffer, "Retrieved unexpected buffer: got %p expected %p", (void *) test, (void *) buffer); + + ccnxTlvDictionary_Release(&packet); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_HashProtectedRegion) +{ + // >1234< + const char string[] = "Hello dev null\n"; + + PARCBuffer *buffer = parcBuffer_Wrap((void *) string, sizeof(string), 0, sizeof(string)); + size_t start = 5; + size_t length = 4; + + CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromContentObjectPacketType(CCNxTlvDictionary_SchemaVersion_V1, buffer); + + ccnxWireFormatMessage_SetProtectedRegionStart(message, start); + ccnxWireFormatMessage_SetProtectedRegionLength(message, length); + + PARCCryptoHasher *hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256); + PARCCryptoHash *hash = ccnxWireFormatMessage_HashProtectedRegion(message, hasher); + + // the correctness of the has is tested in _ccnxWireFormatFacadeV1_ComputeHash + assertNotNull(hash, "Got null hash from a good packet"); + + ccnxWireFormatMessage_Release(&message); + parcCryptoHash_Release(&hash); + parcBuffer_Release(&buffer); + parcCryptoHasher_Release(&hasher); +} + +LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_SetProtectedRegionLength) +{ + const char string[] = "Hello dev null\n"; + PARCBuffer *buffer = parcBuffer_Wrap((void *) string, sizeof(string), 0, sizeof(string)); + + CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromContentObjectPacketType(CCNxTlvDictionary_SchemaVersion_V1, buffer); + + size_t length = 5; + bool success = ccnxWireFormatMessage_SetProtectedRegionLength(message, length); + assertTrue(success, "Failed to put integer in to dictionary"); + + assertTrue(ccnxTlvDictionary_IsValueInteger(message, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedLength), "ProtectedLength not set"); + + ccnxWireFormatMessage_Release(&message); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_SetProtectedRegionStart) +{ + const char string[] = "Hello dev null\n"; + PARCBuffer *buffer = parcBuffer_Wrap((void *) string, sizeof(string), 0, sizeof(string)); + + CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromContentObjectPacketType(CCNxTlvDictionary_SchemaVersion_V1, buffer); + + size_t start = 5; + bool success = ccnxWireFormatMessage_SetProtectedRegionStart(message, start); + assertTrue(success, "Failed to put integer in to dictionary"); + + assertTrue(ccnxTlvDictionary_IsValueInteger(message, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedStart), "ProtectedStart not set"); + + ccnxWireFormatMessage_Release(&message); + parcBuffer_Release(&buffer); +} + +static PARCBuffer * +_iovecToParcBuffer(const CCNxCodecNetworkBufferIoVec *iovec) +{ + PARCBuffer *result = NULL; + + size_t iovcnt = ccnxCodecNetworkBufferIoVec_GetCount((CCNxCodecNetworkBufferIoVec *) iovec); + const struct iovec *array = ccnxCodecNetworkBufferIoVec_GetArray((CCNxCodecNetworkBufferIoVec *) iovec); + + size_t totalbytes = 0; + for (int i = 0; i < iovcnt; i++) { + totalbytes += array[i].iov_len; + } + + result = parcBuffer_Allocate(totalbytes); + for (int i = 0; i < iovcnt; i++) { + parcBuffer_PutArray(result, array[i].iov_len, array[i].iov_base); + } + + parcBuffer_Flip(result); + + + return result; +} + +LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_CreateContentObjectHash) +{ + // >1234< + const char string[] = "Hello dev null\n"; + + PARCBuffer *buffer = parcBuffer_Wrap((void *) string, sizeof(string), 0, sizeof(string)); + + CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromContentObjectPacketType(CCNxTlvDictionary_SchemaVersion_V1, buffer); + + PARCCryptoHash *hash = ccnxWireFormatMessage_CreateContentObjectHash(message); + ccnxWireFormatMessage_Release(&message); + assertNull(hash, "Expect NULL for hash as it hasn't been encoded yet"); + + // We need to create a content object that is hashable + CCNxName *name = ccnxName_CreateFromCString("lci:/test/content"); + CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(name, buffer); + ccnxName_Release(&name); + + // This next stuff is to force an encode/decode to setup hash extents + CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvPacket_DictionaryEncode(contentObject, NULL); + ccnxContentObject_Release(&contentObject); + PARCBuffer *encodedMessage = _iovecToParcBuffer(iovec); + ccnxCodecNetworkBufferIoVec_Release(&iovec); + // Decode + message = ccnxWireFormatMessage_Create(encodedMessage); + CCNxTlvDictionary *dictionary = ccnxWireFormatMessage_GetDictionary(message); + bool success = ccnxCodecTlvPacket_BufferDecode(encodedMessage, dictionary); + assertTrue(success, "Failed to decode buffer"); + parcBuffer_Release(&encodedMessage); + + hash = ccnxWireFormatMessage_CreateContentObjectHash(message); + + // the correctness of the hash is tested in _ccnxWireFormatFacadeV1_ComputeHash + assertNotNull(hash, "Got null hash from a good packet"); + + ccnxWireFormatMessage_Release(&message); + parcCryptoHash_Release(&hash); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_WriteToFile) +{ + const char string[] = "Hello dev null\n"; + PARCBuffer *buffer = parcBuffer_Wrap((void *) string, sizeof(string), 0, sizeof(string)); + CCNxWireFormatMessage *message = ccnxWireFormatMessage_FromInterestPacketType(CCNxTlvDictionary_SchemaVersion_V1, buffer); + + ccnxWireFormatMessage_WriteToFile(message, "/dev/null"); + + ccnxWireFormatMessage_Release(&message); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxWireFormatMessage_SetHopLimit) +{ + uint8_t *data = parcMemory_Allocate(64); + memset(data, 0, 64); + + PARCBuffer *buffer = parcBuffer_Allocate(1); + CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&ParcMemoryMemoryBlock, NULL, 64, data); + CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff); + + CCNxTlvDictionary *packet = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + ccnxWireFormatMessage_PutIoVec((CCNxWireFormatMessage *) packet, iovec); + + ccnxWireFormatMessage_SetHopLimit(packet, 10); + + CCNxCodecNetworkBufferIoVec *test = ccnxWireFormatMessage_GetIoVec((CCNxWireFormatMessage *) packet); + assertTrue(test == iovec, "Failed to get iovec from dictionary, expected %p got %p", (void *) iovec, (void *) test); + + ccnxTlvDictionary_Release(&packet); + parcBuffer_Release(&buffer); + ccnxCodecNetworkBufferIoVec_Release(&iovec); + ccnxCodecNetworkBuffer_Release(&netbuff); +} +LONGBOW_TEST_FIXTURE(Static) +{ + LONGBOW_RUN_TEST_CASE(Static, _getImplForSchema); + LONGBOW_RUN_TEST_CASE(Static, _ccnxWireFormatMessage_CreateWithImpl); +} + +LONGBOW_TEST_FIXTURE_SETUP(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Static) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Static, _ccnxWireFormatMessage_CreateWithImpl) +{ + PARCBuffer *wireFormatV1 = parcBuffer_Wrap(v1_interest_nameA, sizeof(v1_interest_nameA), 0, sizeof(v1_interest_nameA)); + + CCNxWireFormatMessage *message = _ccnxWireFormatMessage_CreateWithImpl(&CCNxWireFormatFacadeV1_Implementation, wireFormatV1); + assertNotNull(message, "Expected to create a V1 CCNxWireFormatMessage"); + + ccnxWireFormatMessage_Release(&message); + parcBuffer_Release(&wireFormatV1); +} + +LONGBOW_TEST_CASE(Static, _getImplForSchema) +{ + CCNxWireFormatMessageInterface *impl = _getImplForSchema(CCNxTlvDictionary_SchemaVersion_V1); + assertTrue(impl = &CCNxWireFormatFacadeV1_Implementation, "Expected to see CCNxWireFormatFacadeV1_Implementation"); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_WireFormatMessage); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} |