diff options
author | Mauro Sardara <msardara+fdio@cisco.com> | 2018-12-18 11:05:49 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@fd.io> | 2018-12-18 11:05:49 +0000 |
commit | cada1143501a48effc483e3873596c22849926b5 (patch) | |
tree | 93a1da95d69b69328a1e7d3621447797f65137c9 /libparc/parc/algol/test | |
parent | 726949d76a7207694d5a1eee84ef134a8e539115 (diff) | |
parent | a45edf23c2463ac9a4723a24792a6c5c89b1e021 (diff) |
Merge "Adding gitreview config file for this branch sub project"
Diffstat (limited to 'libparc/parc/algol/test')
66 files changed, 31437 insertions, 0 deletions
diff --git a/libparc/parc/algol/test/.gitignore b/libparc/parc/algol/test/.gitignore new file mode 100644 index 00000000..b520ab17 --- /dev/null +++ b/libparc/parc/algol/test/.gitignore @@ -0,0 +1,73 @@ +test_parc_ArrayList +test_parc_AtomicInteger +test_parc_Base64 +test_parc_BitVector +test_parc_Buffer +test_parc_BufferComposer +test_parc_BufferDictionary +test_parc_ByteArray +test_parc_ByteBuffer +test_parc_ByteBufferCodec +test_parc_ByteBuffer_Codec +test_parc_Clock +test_parc_Deque +test_parc_Dictionary +test_parc_Digester +test_parc_Digests +test_parc_Digests +test_parc_Display +test_parc_ElasticBuffer +test_parc_ElasticString +test_parc_Environment +test_parc_Event +test_parc_EventBuffer +test_parc_EventQueue +test_parc_EventScheduler +test_parc_EventSignal +test_parc_EventSocket +test_parc_EventTimer +test_parc_Extent +test_parc_ExtentArray +test_parc_FileOutputStream +test_parc_Hash +test_parc_HashCode +test_parc_HashCodeTable +test_parc_HashMap +test_parc_HashMap +test_parc_HashTable +test_parc_InputStream +test_parc_Iterator +test_parc_JSON +test_parc_JSONArray +test_parc_JSONPair +test_parc_JSONParser +test_parc_JSONValue +test_parc_KeyValue +test_parc_KeyedElement +test_parc_LinkedList +test_parc_List +test_parc_Memory +test_parc_Network +test_parc_NewByteBuffer +test_parc_Object +test_parc_ObjectImpl +test_parc_PathName +test_parc_PointerArray +test_parc_PriorityQueue +test_parc_Properties +test_parc_ReadOnlyBuffer +test_parc_SafeMemory +test_parc_SortedList +test_parc_Stack +test_parc_StdlibMemory +test_parc_String +test_parc_StructArray +test_parc_Time +test_parc_Tlv +test_parc_TreeRedBlack +test_parc_TreeMap +test_parc_URI +test_parc_VarInt +test_parc_Varint +test_parc_Vector +test_parc_VectorArray diff --git a/libparc/parc/algol/test/CMakeLists.txt b/libparc/parc/algol/test/CMakeLists.txt new file mode 100644 index 00000000..4199f3de --- /dev/null +++ b/libparc/parc/algol/test/CMakeLists.txt @@ -0,0 +1,76 @@ +# 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_parc_ArrayList + test_parc_AtomicInteger + test_parc_Base64 + test_parc_BitVector + test_parc_Buffer + test_parc_BufferChunker + test_parc_BufferComposer + test_parc_ByteArray + test_parc_Clock + test_parc_Chunker + test_parc_Deque + test_parc_Dictionary + test_parc_Display + test_parc_Environment + test_parc_Event + test_parc_EventBuffer + test_parc_EventQueue + test_parc_EventScheduler + test_parc_EventSignal + test_parc_EventSocket + test_parc_EventTimer + test_parc_File + test_parc_FileChunker + test_parc_FileInputStream + test_parc_FileOutputStream + test_parc_Hash + test_parc_HashCode + test_parc_HashCodeTable + test_parc_HashMap + test_parc_InputStream + test_parc_Iterator + test_parc_JSON + test_parc_JSONArray + test_parc_JSONPair + test_parc_JSONParser + test_parc_JSONValue + test_parc_KeyValue + test_parc_KeyedElement + test_parc_LinkedList + test_parc_List + test_parc_Memory + test_parc_Network + test_parc_Object + test_parc_PathName + test_parc_PriorityQueue + test_parc_Properties + test_parc_RandomAccessFile + test_parc_ReadOnlyBuffer + test_parc_SafeMemory + test_parc_SortedList + test_parc_Stack + test_parc_StdlibMemory + test_parc_String + test_parc_Time + test_parc_TreeMap + test_parc_TreeRedBlack + test_parc_URI + test_parc_URIAuthority + test_parc_URIPath + test_parc_URISegment + test_parc_Varint + test_parc_Vector + ) + +foreach(test ${TestsExpectedToPass}) + AddTest(${test}) +endforeach() + + diff --git a/libparc/parc/algol/test/_test_parc_URI.h b/libparc/parc/algol/test/_test_parc_URI.h new file mode 100644 index 00000000..01d3afae --- /dev/null +++ b/libparc/parc/algol/test/_test_parc_URI.h @@ -0,0 +1,57 @@ +/* + * 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. + */ + +/* + * _test_parc_URI.h + * PARC Algol + */ + +#ifndef PARC_Algol__test_parc_URI_h +#define PARC_Algol__test_parc_URI_h + +#define URI_SCHEME "lci" + +#define URI_AUTHORITY_USERINFO "user:pass" +#define URI_AUTHORITY_USERINFO_2 "user2:pass2" +#define URI_AUTHORITY_HOSTNAME "parc.com" +#define URI_AUTHORITY_HOSTNAME_2 "xerox.com" +#define URI_AUTHORITY_LITERAL_HOSTNAME "127.0.0.1" +#define URI_AUTHORITY_LITERAL_HOSTNAME6 "[::0]" +#define URI_AUTHORITY_LITERAL_HOSTNAME6_2 "[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]" +#define URI_AUTHORITY_PORT_1 "1234" +#define URI_AUTHORITY_PORT_2 "5678" + +#define URI_AUTHORITY URI_AUTHORITY_USERINFO "@" URI_AUTHORITY_HOSTNAME ":" URI_AUTHORITY_PORT_1 +#define URI_AUTHORITY_DIFFERENT_PORT URI_AUTHORITY_USERINFO "@" URI_AUTHORITY_HOSTNAME ":" URI_AUTHORITY_PORT_2 +#define URI_AUTHORITY_DIFFERENT_HOST URI_AUTHORITY_USERINFO "@" URI_AUTHORITY_HOSTNAME_2 ":" URI_AUTHORITY_PORT_1 +#define URI_AUTHORITY_LITERAL_HOST URI_AUTHORITY_USERINFO "@" URI_AUTHORITY_LITERAL_HOSTNAME ":" URI_AUTHORITY_PORT_1 +#define URI_AUTHORITY_LITERAL_HOST6 URI_AUTHORITY_USERINFO "@" URI_AUTHORITY_LITERAL_HOSTNAME6 ":" URI_AUTHORITY_PORT_1 +#define URI_AUTHORITY_LITERAL_HOST6_2 URI_AUTHORITY_USERINFO "@" URI_AUTHORITY_LITERAL_HOSTNAME6_2 ":" URI_AUTHORITY_PORT_1 +#define URI_AUTHORITY_DIFFERENT_USER URI_AUTHORITY_USERINFO_2 "@" URI_AUTHORITY_HOSTNAME ":" URI_AUTHORITY_PORT_1 + +#define URI_PATH_SEGMENT "%00%01%02-.%03%04_%05%06%07%08%09abcdefghijklmnopqrstuvwxyz" +#define URI_PATH_SEGMENT_WITH_SLASHES URI_PATH_SEGMENT "//////" + +#define URI_PATH "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT + +#define URI_QUERY "x=1&y=2&z=3" + +#define URI_FRAGMENT "alphabetagamma" + +#define URI_FULL URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH "?" URI_QUERY "#" URI_FRAGMENT + +char *TEST_URI_SCHEME = URI_SCHEME; +char *TEST_URI_AUTHORITY = URI_AUTHORITY; +#endif // PARC_Algol__test_parc_URI_h diff --git a/libparc/parc/algol/test/data.json b/libparc/parc/algol/test/data.json new file mode 100644 index 00000000..a146f6ff --- /dev/null +++ b/libparc/parc/algol/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/libparc/parc/algol/test/test_parc_ArrayList.c b/libparc/parc/algol/test/test_parc_ArrayList.c new file mode 100755 index 00000000..9e387a28 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_ArrayList.c @@ -0,0 +1,658 @@ +/* + * 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 "../parc_ArrayList.c" +#include <LongBow/unit-test.h> + +#include <stdio.h> +#include <string.h> + +#include <parc/algol/parc_SafeMemory.h> +#include <parc/testing/parc_ObjectTesting.h> + +#include <parc/algol/parc_Buffer.h> + +LONGBOW_TEST_RUNNER(PARC_ArrayList) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); + LONGBOW_RUN_TEST_FIXTURE(Errors); +} + +LONGBOW_TEST_RUNNER_SETUP(PARC_ArrayList) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(PARC_ArrayList) +{ + 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; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Add); + LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_AddAll); + LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Copy); + LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Destroy); + + LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_CustomDestroyer); + + LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Equals_Contract); + LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Equals_Contract_Deep); + + LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_FromInitialCapacity); + LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Get); + LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_New); + LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Size); + LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Remove_AtIndex_First); + LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Remove_AtIndex); + LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Remove_AtIndex_Last); + LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_RemoveAndDestroy_AtIndex_First); + LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_RemoveAndDestroy_AtIndex); + LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_RemoveAndDestroy_AtIndex_Last); + LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_InsertAtIndex); + LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_InsertAtIndex_Empty); + LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_InsertAtIndex_First); + LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_InsertAtIndex_Last); + LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_IsEmpty); +} + +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 %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, PARC_ArrayList_Add) +{ + PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction); + + parcArrayList_Add(array, 0); + size_t actual = parcArrayList_Size(array); + + assertTrue(1 == actual, "Expected=%d, actual=%zu", 1, actual); + + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARC_ArrayList_AddAll) +{ + PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction); + + void *elements[] = { + strdup("a"), + strdup("b"), + strdup("c"), + }; + + parcArrayList_AddAll(array, elements, 3); + size_t actual = parcArrayList_Size(array); + + assertTrue(3 == actual, "Expected=%d, actual=%zu", 3, actual); + + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARC_ArrayList_Copy) +{ + char a[] = "apple"; + char b[] = "bananna"; + char c[] = "cherry"; + + PARCArrayList *array = parcArrayList_Create(NULL); + parcArrayList_Add(array, a); + parcArrayList_Add(array, b); + parcArrayList_Add(array, c); + + PARCArrayList *copy = parcArrayList_Copy(array); + assertTrue(parcArrayList_Equals(array, copy), "Expected arrays to be equal."); + + parcArrayList_Destroy(©); + parcArrayList_Destroy(&array); +} + +static void +testCustomDestroyer(void **bufferVoidPtr) +{ + PARCBuffer **bufferPtr = (PARCBuffer **) bufferVoidPtr; + parcBuffer_Release(bufferPtr); +} + +LONGBOW_TEST_CASE(Global, PARC_ArrayList_CustomDestroyer) +{ + size_t before = parcMemory_Outstanding(); + + PARCArrayList *array = parcArrayList_Create(testCustomDestroyer); + PARCBuffer *buffer = parcBuffer_Allocate(20); + parcArrayList_Add(array, parcBuffer_Acquire(buffer)); + parcBuffer_Release(&buffer); + parcArrayList_Destroy(&array); + + size_t after = parcMemory_Outstanding(); + + assertTrue(before == after, "Memory imbalance after using custom destroy, expected %zu got %zu", before, after); +} + + +LONGBOW_TEST_CASE(Global, PARC_ArrayList_Destroy) +{ + PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction); + + parcArrayList_Destroy(&array); + assertNull(array, "Expected null."); +} + +LONGBOW_TEST_CASE(Global, PARC_ArrayList_Equals_Empty) +{ + PARCArrayList *a = parcArrayList_Create(parcArrayList_StdlibFreeFunction); + PARCArrayList *b = parcArrayList_Create(parcArrayList_StdlibFreeFunction); + assertTrue(parcArrayList_Equals(a, b), "Equal values were expected to be equal"); + + parcArrayList_Destroy(&a); + parcArrayList_Destroy(&b); +} + +LONGBOW_TEST_CASE(Global, PARC_ArrayList_Equals_Same) +{ + PARCArrayList *a = parcArrayList_Create(parcArrayList_StdlibFreeFunction); + assertTrue(parcArrayList_Equals(a, a), "Expected the same array list to be equal to itself."); + + parcArrayList_Destroy(&a); +} + +LONGBOW_TEST_CASE(Global, PARC_ArrayList_Equals_Contract) +{ + char a[] = "apple"; + char b[] = "bananna"; + char c[] = "cherry"; + char d[] = "potato"; + + PARCArrayList *x = parcArrayList_Create(NULL); + parcArrayList_Add(x, a); + parcArrayList_Add(x, b); + parcArrayList_Add(x, c); + + PARCArrayList *y = parcArrayList_Create(NULL); + parcArrayList_Add(y, a); + parcArrayList_Add(y, b); + parcArrayList_Add(y, c); + + PARCArrayList *z = parcArrayList_Create(NULL); + parcArrayList_Add(z, a); + parcArrayList_Add(z, b); + parcArrayList_Add(z, c); + + PARCArrayList *u1 = parcArrayList_Create(NULL); + parcArrayList_Add(u1, a); + parcArrayList_Add(u1, b); + + PARCArrayList *u2 = parcArrayList_Create(NULL); + parcArrayList_Add(u1, a); + parcArrayList_Add(u2, b); + parcArrayList_Add(u2, c); + parcArrayList_Add(u2, c); + + PARCArrayList *u3 = parcArrayList_Create(NULL); + parcArrayList_Add(u3, a); + parcArrayList_Add(u3, b); + parcArrayList_Add(u3, d); + + parcObjectTesting_AssertEqualsFunction(parcArrayList_Equals, x, y, z, u1, u2, u3); + + parcArrayList_Destroy(&x); + parcArrayList_Destroy(&y); + parcArrayList_Destroy(&z); + parcArrayList_Destroy(&u1); + parcArrayList_Destroy(&u2); + parcArrayList_Destroy(&u3); +} + +static bool +stringEquals(void *x, void *y) +{ + return strcmp((char *) x, (char *) y) == 0; +} + +LONGBOW_TEST_CASE(Global, PARC_ArrayList_Equals_Contract_Deep) +{ + char a[] = "apple"; + char b[] = "bananna"; + char c[] = "cherry"; + char d[] = "potato"; + + PARCArrayList *x = parcArrayList_Create_Capacity(stringEquals, NULL, 0); + parcArrayList_Add(x, a); + parcArrayList_Add(x, b); + parcArrayList_Add(x, c); + + PARCArrayList *y = parcArrayList_Create_Capacity(stringEquals, NULL, 0); + parcArrayList_Add(y, a); + parcArrayList_Add(y, b); + parcArrayList_Add(y, c); + + PARCArrayList *z = parcArrayList_Create_Capacity(stringEquals, NULL, 0); + parcArrayList_Add(z, a); + parcArrayList_Add(z, b); + parcArrayList_Add(z, c); + + PARCArrayList *u1 = parcArrayList_Create_Capacity(stringEquals, NULL, 0); + parcArrayList_Add(u1, a); + parcArrayList_Add(u1, b); + + PARCArrayList *u2 = parcArrayList_Create_Capacity(stringEquals, NULL, 0); + parcArrayList_Add(u2, a); + parcArrayList_Add(u2, b); + parcArrayList_Add(u2, c); + parcArrayList_Add(u2, c); + + PARCArrayList *u3 = parcArrayList_Create_Capacity(stringEquals, NULL, 0); + parcArrayList_Add(u3, a); + parcArrayList_Add(u3, b); + parcArrayList_Add(u3, d); + + parcObjectTesting_AssertEqualsFunction(parcArrayList_Equals, x, y, z, u1, u2, u3); + + parcArrayList_Destroy(&x); + parcArrayList_Destroy(&y); + parcArrayList_Destroy(&z); + parcArrayList_Destroy(&u1); + parcArrayList_Destroy(&u2); + parcArrayList_Destroy(&u3); +} + +LONGBOW_TEST_CASE(Local, PARC_ArrayList_EnsureRemaining_Empty) +{ + PARCArrayList *array = parcArrayList_Create(NULL); + size_t expected = 4; + _ensureRemaining(array, expected); + + size_t actual = _remaining(array); + + assertTrue(actual >= expected, "Expected >= %zd, actual=%zd", expected, actual); + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Local, PARC_ArrayList_EnsureRemaining_NonEmpty) +{ + PARCArrayList *array = parcArrayList_Create(NULL); + parcArrayList_Add(array, 0); + + size_t expected = 5; + _ensureRemaining(array, expected); + + size_t actual = _remaining(array); + + assertTrue(actual >= expected, "Expected >= %zd, actual=%zd", expected, actual); + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARC_ArrayList_FromInitialCapacity) +{ + PARCArrayList *array = parcArrayList_Create_Capacity(NULL, parcArrayList_StdlibFreeFunction, 10); + size_t actual = parcArrayList_Size(array); + + assertTrue(0 == actual, "Expected=%d, actual=%zu", 0, actual); + + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARC_ArrayList_Get) +{ + PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction); + + char *expected = strdup("Hello World"); + parcArrayList_Add(array, expected); + + char *actual = parcArrayList_Get(array, 0); + + assertTrue(expected == actual, "Expected=%p, actual=%p", (void *) expected, (void *) actual); + + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARC_ArrayList_New) +{ + PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction); + size_t size = parcArrayList_Size(array); + assertTrue(0 == size, "Expected %d actual=%zu", 0, size); + + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARC_ArrayList_Size) +{ + PARCArrayList *array = parcArrayList_Create(NULL); + parcArrayList_Add(array, 0); + + size_t size = parcArrayList_Size(array); + assertTrue(1 == size, "Expected %d actual=%zu", 1, size); + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARC_ArrayList_IsEmpty) +{ + PARCArrayList *array = parcArrayList_Create(NULL); + assertTrue(parcArrayList_IsEmpty(array), "Expected a new array to be empty."); + + parcArrayList_Add(array, 0); + assertFalse(parcArrayList_IsEmpty(array), "Expected an array with more than zero elements to be empty."); + + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARC_ArrayList_InsertAtIndex) +{ + PARCArrayList *array = parcArrayList_Create(NULL); + + parcArrayList_Add(array, (void *) 1); + parcArrayList_Add(array, (void *) 2); + size_t actual = parcArrayList_Size(array); + + assertTrue(2 == actual, "Expected=%d, actual=%zu", 2, actual); + + parcArrayList_InsertAtIndex(array, 1, (void *) 3); + + actual = parcArrayList_Size(array); + assertTrue(3 == actual, "Expected=%d, actual=%zu", 3, actual); + + void *element0 = parcArrayList_Get(array, 0); + assertTrue(element0 == (void *) 1, "Element 1 moved?"); + + void *element1 = parcArrayList_Get(array, 1); + assertTrue(element1 == (void *) 3, "Element 1 moved?"); + + void *element2 = parcArrayList_Get(array, 2); + assertTrue(element2 == (void *) 2, "Element 1 moved?"); + + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARC_ArrayList_InsertAtIndex_Empty) +{ + PARCArrayList *array = parcArrayList_Create(NULL); + + parcArrayList_InsertAtIndex(array, 0, (void *) 3); + + size_t actual = parcArrayList_Size(array); + + assertTrue(1 == actual, "Expected=%d, actual=%zu", 1, actual); + + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARC_ArrayList_InsertAtIndex_First) +{ + PARCArrayList *array = parcArrayList_Create(NULL); + + parcArrayList_Add(array, (void *) 1); + parcArrayList_InsertAtIndex(array, 0, (void *) 2); + size_t actual = parcArrayList_Size(array); + + assertTrue(2 == actual, "Expected=%d, actual=%zu", 2, actual); + + void *element0 = parcArrayList_Get(array, 0); + assertTrue(element0 == (void *) 2, "Element 1 moved?"); + + void *element1 = parcArrayList_Get(array, 1); + assertTrue(element1 == (void *) 1, "Element 1 moved?"); + + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARC_ArrayList_InsertAtIndex_Last) +{ + PARCArrayList *array = parcArrayList_Create(NULL); + + parcArrayList_Add(array, (void *) 1); + parcArrayList_Add(array, (void *) 2); + size_t actual = parcArrayList_Size(array); + + assertTrue(2 == actual, "Expected=%d, actual=%zu", 2, actual); + + parcArrayList_InsertAtIndex(array, 2, (void *) 3); + + actual = parcArrayList_Size(array); + assertTrue(3 == actual, "Expected=%d, actual=%zu", 3, actual); + + void *element0 = parcArrayList_Get(array, 0); + assertTrue(element0 == (void *) 1, "Element 1 moved?"); + + void *element1 = parcArrayList_Get(array, 1); + assertTrue(element1 == (void *) 2, "Element 1 moved?"); + + void *element2 = parcArrayList_Get(array, 2); + assertTrue(element2 == (void *) 3, "Element 1 moved?"); + + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARC_ArrayList_Remove_AtIndex_First) +{ + char a[] = "apple"; + char b[] = "bananna"; + char c[] = "cherry"; + + PARCArrayList *array = parcArrayList_Create(NULL); + parcArrayList_Add(array, a); + parcArrayList_Add(array, b); + parcArrayList_Add(array, c); + + PARCArrayList *expected = parcArrayList_Create(NULL); + parcArrayList_Add(expected, b); + parcArrayList_Add(expected, c); + + void *removedElement = parcArrayList_RemoveAtIndex(array, 0); + + assertTrue(removedElement == a, "Expected "); + assertTrue(parcArrayList_Equals(expected, array), "Expected "); + + parcArrayList_Destroy(&expected); + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARC_ArrayList_Remove_AtIndex) +{ + char a[] = "apple"; + char b[] = "bananna"; + char c[] = "cherry"; + + PARCArrayList *array = parcArrayList_Create(NULL); + parcArrayList_Add(array, a); + parcArrayList_Add(array, b); + parcArrayList_Add(array, c); + + PARCArrayList *expected = parcArrayList_Create(NULL); + parcArrayList_Add(expected, a); + parcArrayList_Add(expected, c); + + void *removedElement = parcArrayList_RemoveAtIndex(array, 1); + + assertTrue(removedElement == b, "Expected "); + assertTrue(parcArrayList_Equals(expected, array), "Expected "); + + parcArrayList_Destroy(&expected); + parcArrayList_Destroy(&array); +} + + +LONGBOW_TEST_CASE(Global, PARC_ArrayList_Remove_AtIndex_Last) +{ + char a[] = "apple"; + char b[] = "bananna"; + char c[] = "cherry"; + + PARCArrayList *array = parcArrayList_Create(NULL); + parcArrayList_Add(array, a); + parcArrayList_Add(array, b); + parcArrayList_Add(array, c); + + PARCArrayList *expected = parcArrayList_Create(NULL); + parcArrayList_Add(expected, a); + parcArrayList_Add(expected, b); + + void *removedElement = parcArrayList_RemoveAtIndex(array, 2); + + assertTrue(removedElement == c, "Expected "); + assertTrue(parcArrayList_Equals(expected, array), "Expected "); + + parcArrayList_Destroy(&expected); + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARC_ArrayList_RemoveAndDestroy_AtIndex_First) +{ + char a[] = "apple"; + char b[] = "bananna"; + char c[] = "cherry"; + + PARCArrayList *array = parcArrayList_Create(NULL); + parcArrayList_Add(array, a); + parcArrayList_Add(array, b); + parcArrayList_Add(array, c); + + PARCArrayList *expected = parcArrayList_Create(NULL); + parcArrayList_Add(expected, b); + parcArrayList_Add(expected, c); + + parcArrayList_RemoveAndDestroyAtIndex(array, 0); + + assertTrue(parcArrayList_Equals(expected, array), "Expected "); + + parcArrayList_Destroy(&expected); + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARC_ArrayList_RemoveAndDestroy_AtIndex) +{ + char a[] = "apple"; + char b[] = "bananna"; + char c[] = "cherry"; + + PARCArrayList *array = parcArrayList_Create(NULL); + parcArrayList_Add(array, a); + parcArrayList_Add(array, b); + parcArrayList_Add(array, c); + + PARCArrayList *expected = parcArrayList_Create(NULL); + parcArrayList_Add(expected, a); + parcArrayList_Add(expected, c); + + parcArrayList_RemoveAndDestroyAtIndex(array, 1); + + assertTrue(parcArrayList_Equals(expected, array), "Expected "); + + parcArrayList_Destroy(&expected); + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARC_ArrayList_RemoveAndDestroy_AtIndex_Last) +{ + char a[] = "apple"; + char b[] = "bananna"; + char c[] = "cherry"; + + PARCArrayList *array = parcArrayList_Create(NULL); + parcArrayList_Add(array, a); + parcArrayList_Add(array, b); + parcArrayList_Add(array, c); + + PARCArrayList *expected = parcArrayList_Create(NULL); + parcArrayList_Add(expected, a); + parcArrayList_Add(expected, b); + + parcArrayList_RemoveAndDestroyAtIndex(array, 2); + + assertTrue(parcArrayList_Equals(expected, array), "Expected "); + + parcArrayList_Destroy(&expected); + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, PARC_ArrayList_EnsureRemaining_Empty); + LONGBOW_RUN_TEST_CASE(Local, PARC_ArrayList_EnsureRemaining_NonEmpty); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Errors) +{ + LONGBOW_RUN_TEST_CASE(Errors, PARC_ArrayList_InsertAtIndex_OutOfCapacity); +} + +LONGBOW_TEST_FIXTURE_SETUP(Errors) +{ + PARCArrayList *array = parcArrayList_Create(NULL); + + longBowTestCase_SetClipBoardData(testCase, array); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Errors) +{ + PARCArrayList *array = longBowTestCase_GetClipBoardData(testCase); + parcArrayList_Destroy(&array); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + if (outstandingAllocations != 0) { + printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE_EXPECTS(Errors, PARC_ArrayList_InsertAtIndex_OutOfCapacity, .event = &LongBowAssertEvent) +{ + PARCArrayList *array = longBowTestCase_GetClipBoardData(testCase); + + parcArrayList_Add(array, (void *) 1); + parcArrayList_Add(array, (void *) 2); + + parcArrayList_InsertAtIndex(array, 200, (void *) 3); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(PARC_ArrayList); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_AtomicInteger.c b/libparc/parc/algol/test/test_parc_AtomicInteger.c new file mode 100644 index 00000000..9bd1b99a --- /dev/null +++ b/libparc/parc/algol/test/test_parc_AtomicInteger.c @@ -0,0 +1,156 @@ +/* + * 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 "../parc_AtomicInteger.c" + +#include <inttypes.h> +#include <stdio.h> + +#include <LongBow/testing.h> +#include <LongBow/debugging.h> + +LONGBOW_TEST_RUNNER(test_parc_AtomicInteger) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Threaded); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(test_parc_AtomicInteger) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_AtomicInteger) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcAtomicInteger_Uint32Increment); + LONGBOW_RUN_TEST_CASE(Global, parcAtomicInteger_Uint32Decrement); + LONGBOW_RUN_TEST_CASE(Global, parcAtomicInteger_Uint64Increment); + LONGBOW_RUN_TEST_CASE(Global, parcAtomicInteger_Uint64Decrement); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, parcAtomicInteger_Uint32Increment) +{ + uint32_t value = 0; + parcAtomicInteger_Uint32Increment(&value); + assertTrue(value == 1, "Expected 1, actual, %u", value); +} + +LONGBOW_TEST_CASE(Global, parcAtomicInteger_Uint32Decrement) +{ + uint32_t value = 0; + parcAtomicInteger_Uint32Increment(&value); + assertTrue(value == 1, "Expected 1, actual, %u", value); +} + +LONGBOW_TEST_CASE(Global, parcAtomicInteger_Uint64Increment) +{ + uint64_t value = 0; + parcAtomicInteger_Uint64Increment(&value); + assertTrue(value == 1, "Expected 1, actual, %" PRIu64 "", value); +} + +LONGBOW_TEST_CASE(Global, parcAtomicInteger_Uint64Decrement) +{ + uint64_t value = 0; + parcAtomicInteger_Uint64Increment(&value); + assertTrue(value == 1, "Expected 1, actual, %" PRIu64 "", value); +} + +LONGBOW_TEST_FIXTURE(Threaded) +{ + LONGBOW_RUN_TEST_CASE(Threaded, collaborative); +} + +LONGBOW_TEST_FIXTURE_SETUP(Threaded) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Threaded) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +static void * +collaborator_A(void *data) +{ + uint32_t *valuePointer = (uint32_t *) data; + uint32_t contribution = 0; + while (*valuePointer < 1000000) { + parcAtomicInteger_Uint32Increment(valuePointer); + contribution++; + } + printf("A contribution %d\n", contribution); + pthread_exit((void *) NULL); +} + +static void * +collaborator_B(void *data) +{ + uint32_t *valuePointer = (uint32_t *) data; + + uint32_t contribution = 0; + while (*valuePointer < 1000000) { + parcAtomicInteger_Uint32Increment(valuePointer); + contribution++; + } + + printf("B contribution %d\n", contribution); + pthread_exit((void *) NULL); +} + +LONGBOW_TEST_CASE(Threaded, collaborative) +{ + uint32_t value = 0; + + pthread_t thread_A; + pthread_t thread_B; + + pthread_create(&thread_A, NULL, collaborator_A, &value); + pthread_create(&thread_B, NULL, collaborator_B, &value); + + pthread_join(thread_A, NULL); + pthread_join(thread_B, NULL); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_AtomicInteger); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_Base64.c b/libparc/parc/algol/test/test_parc_Base64.c new file mode 100755 index 00000000..4509ded3 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_Base64.c @@ -0,0 +1,414 @@ +/* + * 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 <LongBow/unit-test.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../parc_Base64.c" +#include <parc/algol/parc_SafeMemory.h> + +LONGBOW_TEST_RUNNER(parc_Base64) +{ + // 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(parc_Base64) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_Base64) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcBase64_Decode); + LONGBOW_RUN_TEST_CASE(Global, parcBase64_Decode_Linefeeds); + LONGBOW_RUN_TEST_CASE(Global, parcBase64_Encode); + LONGBOW_RUN_TEST_CASE(Global, parcBase64_Encode_Binary); +} + +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 %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +static struct testvector_s { + char *plaintext; + char *encoded; +} testvector[] = { + // Test vectors from RFC 4648 + { .plaintext = "", .encoded = "" }, + { .plaintext = "f", .encoded = "Zg==" }, + { .plaintext = "fo", .encoded = "Zm8=" }, + { .plaintext = "foo", .encoded = "Zm9v" }, + { .plaintext = "foob", .encoded = "Zm9vYg==" }, + { .plaintext = "fooba", .encoded = "Zm9vYmE=" }, + { .plaintext = "foobar", .encoded = "Zm9vYmFy" }, + { .plaintext = NULL, .encoded = NULL } +}; + +LONGBOW_TEST_CASE(Global, parcBase64_Decode) +{ + int i = 0; + while (testvector[i].plaintext != NULL) { + PARCBufferComposer *input = parcBufferComposer_Create(); + PARCBufferComposer *truth = parcBufferComposer_Create(); + PARCBufferComposer *output = parcBufferComposer_Create(); + + parcBufferComposer_PutString(input, testvector[i].encoded); + PARCBuffer *inputBuffer = parcBufferComposer_ProduceBuffer(input); + parcBufferComposer_PutString(truth, testvector[i].plaintext); + PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth); + + parcBase64_Decode(output, parcBufferComposer_GetBuffer(input)); + PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output); + + assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer), + "encoding, expected '%s' got '%s'", + parcBuffer_ToHexString(truthBuffer), + parcBuffer_ToHexString(outputBuffer)); + + i++; + + parcBuffer_Release(&inputBuffer); + parcBuffer_Release(&truthBuffer); + parcBuffer_Release(&outputBuffer); + + parcBufferComposer_Release(&input); + parcBufferComposer_Release(&output); + parcBufferComposer_Release(&truth); + } +} + +LONGBOW_TEST_CASE(Global, parcBase64_Decode_Linefeeds) +{ + PARCBufferComposer *input = parcBufferComposer_Create(); + PARCBufferComposer *truth = parcBufferComposer_Create(); + PARCBufferComposer *output = parcBufferComposer_Create(); + + char plaintext[] = "It was a dark and stormy night, and all through the code not bit was stirring.\x0A"; + char encoded_with_crlf[] = "SXQg" "\x0D\x0A" "d2FzIGEgZGFyayBhbmQgc3Rvcm15IG5pZ2h0LCBhbmQgYWxsIHRocm91Z2gg" "\x0D\x0A" "dGhlIGNvZGUgbm90IGJpdCB3YXMgc3RpcnJpbmcuCg=="; + + parcBufferComposer_PutString(input, encoded_with_crlf); + PARCBuffer *inputBuffer = parcBufferComposer_ProduceBuffer(input); + + parcBufferComposer_PutString(truth, plaintext); + PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth); + + parcBase64_Decode(output, parcBufferComposer_GetBuffer(input)); + PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output); + assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer), + "encoding, expected '%s' got '%s'", + parcBuffer_ToHexString(truthBuffer), + parcBuffer_ToHexString(outputBuffer)); + + parcBuffer_Release(&inputBuffer); + parcBuffer_Release(&truthBuffer); + parcBuffer_Release(&outputBuffer); + + parcBufferComposer_Release(&input); + parcBufferComposer_Release(&output); + parcBufferComposer_Release(&truth); +} + + +LONGBOW_TEST_CASE(Global, parcBase64_Encode) +{ + int i = 0; + while (testvector[i].plaintext != NULL) { + PARCBufferComposer *input = parcBufferComposer_Create(); + PARCBufferComposer *truth = parcBufferComposer_Create(); + PARCBufferComposer *output = parcBufferComposer_Create(); + + parcBufferComposer_PutString(input, testvector[i].plaintext); + PARCBuffer *inputBuffer = parcBufferComposer_ProduceBuffer(input); + parcBufferComposer_PutString(truth, testvector[i].encoded); + PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth); + + parcBase64_Encode(output, parcBufferComposer_GetBuffer(input)); + PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output); + assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer), + "encoding, expected '%s' got '%s'", + parcBuffer_ToHexString(truthBuffer), + parcBuffer_ToHexString(outputBuffer)); + + i++; + + parcBuffer_Release(&inputBuffer); + parcBuffer_Release(&truthBuffer); + parcBuffer_Release(&outputBuffer); + + parcBufferComposer_Release(&input); + parcBufferComposer_Release(&output); + parcBufferComposer_Release(&truth); + } +} + +LONGBOW_TEST_CASE(Global, parcBase64_Encode_Binary) +{ + uint8_t zero[] = { 0 }; + + // 1 2 3 4 5 6 7 + char *truthvector[] = { "AA==", "AAA=", "AAAA", "AAAAAA==", "AAAAAAA=", "AAAAAAAA", "AAAAAAAAAA==" }; + + for (int i = 0; i < sizeof(truthvector) / sizeof(truthvector[0]); i++) { + PARCBufferComposer *input = parcBufferComposer_Create(); + PARCBufferComposer *truth = parcBufferComposer_Create(); + PARCBufferComposer *output = parcBufferComposer_Create(); + + parcBufferComposer_PutArray(truth, (uint8_t *) truthvector[i], strlen(truthvector[i])); + PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth); + + // just keep apending a zero to make it longer + parcBuffer_SetLimit(parcBufferComposer_GetBuffer(input), parcBuffer_Capacity(parcBufferComposer_GetBuffer(input))); + parcBuffer_SetPosition(parcBufferComposer_GetBuffer(input), i); + parcBufferComposer_PutArray(input, zero, 1); + PARCBuffer *inputBuffer = parcBufferComposer_ProduceBuffer(input); + + parcBase64_Encode(output, parcBufferComposer_GetBuffer(input)); + PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output); + + assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer), + "encoding, expected '%s' got '%s'", + parcBuffer_ToHexString(truthBuffer), + parcBuffer_ToHexString(outputBuffer)); + + parcBuffer_Release(&inputBuffer); + parcBuffer_Release(&truthBuffer); + parcBuffer_Release(&outputBuffer); + + parcBufferComposer_Release(&input); + parcBufferComposer_Release(&output); + parcBufferComposer_Release(&truth); + } +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, encodeWithPad_0); + LONGBOW_RUN_TEST_CASE(Local, encodeWithPad_1); + LONGBOW_RUN_TEST_CASE(Local, encodeWithPad_2); + LONGBOW_RUN_TEST_CASE(Local, decode_invalid); + LONGBOW_RUN_TEST_CASE(Local, decode_1); + LONGBOW_RUN_TEST_CASE(Local, decode_2); + LONGBOW_RUN_TEST_CASE(Local, decode_3); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +/** + * This will encode "foo" + */ +LONGBOW_TEST_CASE(Local, encodeWithPad_0) +{ + PARCBufferComposer *output = parcBufferComposer_Create(); + uint8_t input[] = "foobar"; + PARCBufferComposer *truth = parcBufferComposer_Create(); + parcBufferComposer_PutString(truth, "Zm9v"); + PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth); + + _encodeWithPad(output, input, 0); + PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output); + assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer), + "Failed 3-byte encode, expected '%s' got '%s'", + parcBuffer_ToHexString(truthBuffer), + parcBuffer_ToHexString(outputBuffer)); + + parcBuffer_Release(&truthBuffer); + parcBuffer_Release(&outputBuffer); + + parcBufferComposer_Release(&output); + parcBufferComposer_Release(&truth); +} + +/** + * This will encode "fo" because we tell it there's 1 pad byte + */ +LONGBOW_TEST_CASE(Local, encodeWithPad_1) +{ + PARCBufferComposer *output = parcBufferComposer_Create(); + uint8_t input[] = "foobar"; + PARCBufferComposer *truth = parcBufferComposer_Create(); + parcBufferComposer_PutString(truth, "Zm8="); + PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth); + + _encodeWithPad(output, input, 1); + PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output); + + assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer), + "Failed 3-byte encode, expected '%s' got '%s'", + parcBuffer_ToHexString(truthBuffer), + parcBuffer_ToHexString(outputBuffer)); + + parcBuffer_Release(&truthBuffer); + parcBuffer_Release(&outputBuffer); + + parcBufferComposer_Release(&output); + parcBufferComposer_Release(&truth); +} + +/** + * This will encode "f" because we tell it there's 2 pad byte + */ +LONGBOW_TEST_CASE(Local, encodeWithPad_2) +{ + PARCBufferComposer *output = parcBufferComposer_Create(); + uint8_t input[] = "foobar"; + PARCBufferComposer *truth = parcBufferComposer_Create(); + parcBufferComposer_PutString(truth, "Zg=="); + PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth); + + _encodeWithPad(output, input, 2); + PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output); + + assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer), + "Failed 3-byte encode, expected '%s' got '%s'", + parcBuffer_ToHexString(truthBuffer), + parcBuffer_ToHexString(outputBuffer)); + + parcBuffer_Release(&truthBuffer); + parcBuffer_Release(&outputBuffer); + + parcBufferComposer_Release(&output); + parcBufferComposer_Release(&truth); +} + + +LONGBOW_TEST_CASE(Local, decode_1) +{ + PARCBufferComposer *output = parcBufferComposer_Create(); + uint8_t input[] = "Zg=="; + PARCBufferComposer *truth = parcBufferComposer_Create(); + parcBufferComposer_PutString(truth, "f"); + PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth); + + bool success = _decode(output, input); + assertTrue(success, "Valid base64 failed decode"); + + PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output); + assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer), + "Failed 3-byte encode, expected '%s' got '%s'", + parcBuffer_ToHexString(truthBuffer), + parcBuffer_ToHexString(outputBuffer)); + + parcBuffer_Release(&truthBuffer); + parcBuffer_Release(&outputBuffer); + + parcBufferComposer_Release(&output); + parcBufferComposer_Release(&truth); +} + +LONGBOW_TEST_CASE(Local, decode_2) +{ + PARCBufferComposer *output = parcBufferComposer_Create(); + uint8_t input[] = "Zm8="; + PARCBufferComposer *truth = parcBufferComposer_Create(); + parcBufferComposer_PutString(truth, "fo"); + PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth); + + bool success = _decode(output, input); + assertTrue(success, "Valid base64 failed decode"); + + PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output); + + assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer), + "Failed 3-byte encode, expected '%s' got '%s'", + parcBuffer_ToHexString(truthBuffer), + parcBuffer_ToHexString(outputBuffer)); + + parcBuffer_Release(&truthBuffer); + parcBuffer_Release(&outputBuffer); + + parcBufferComposer_Release(&output); + parcBufferComposer_Release(&truth); +} + +LONGBOW_TEST_CASE(Local, decode_3) +{ + PARCBufferComposer *output = parcBufferComposer_Create(); + uint8_t input[] = "Zm9v"; + PARCBufferComposer *truth = parcBufferComposer_Create(); + parcBufferComposer_PutString(truth, "foo"); + PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth); + + bool success = _decode(output, input); + assertTrue(success, "Valid base64 failed decode"); + PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output); + + assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer), + "Failed 3-byte encode, expected '%s' got '%s'", + parcBuffer_ToHexString(truthBuffer), + parcBuffer_ToHexString(outputBuffer)); + + parcBuffer_Release(&truthBuffer); + parcBuffer_Release(&outputBuffer); + + parcBufferComposer_Release(&output); + parcBufferComposer_Release(&truth); +} + +LONGBOW_TEST_CASE(Local, decode_invalid) +{ + PARCBufferComposer *output = parcBufferComposer_Create(); + uint8_t input[] = "@@@@"; + + bool success = _decode(output, input); + assertFalse(success, "Invalid base64 somehow decoded"); + + parcBufferComposer_Release(&output); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Base64); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_BitVector.c b/libparc/parc/algol/test/test_parc_BitVector.c new file mode 100755 index 00000000..9a4d0806 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_BitVector.c @@ -0,0 +1,438 @@ +/* + * 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 <LongBow/unit-test.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../parc_BitVector.c" + +#include <stdio.h> +#include <parc/algol/parc_SafeMemory.h> +#include <limits.h> + +LONGBOW_TEST_RUNNER(parc_BitVector) +{ + // 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(parc_BitVector) +{ + 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(parc_BitVector) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Create_Release); + LONGBOW_RUN_TEST_CASE(Global, parcBitVector_SetClear); + LONGBOW_RUN_TEST_CASE(Global, parcBitVector_SetVector); + LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Reset); + LONGBOW_RUN_TEST_CASE(Global, parcBitVector_ClearVector); + LONGBOW_RUN_TEST_CASE(Global, parcBitVector_NextBitSet); + LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Get); + LONGBOW_RUN_TEST_CASE(Global, parcBitVector_ToString); + LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Copy); + LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Equals); + LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Contains); + LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Set); + LONGBOW_RUN_TEST_CASE(Global, parcBitVector_And); + LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Or); + LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Shift); +} + +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 %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, parcBitVector_Create_Release) +{ + PARCBitVector *parcBitVector = parcBitVector_Create(); + assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer"); + PARCBitVector *reference = parcBitVector; + parcBitVector_Acquire(reference); + parcBitVector_Release(&parcBitVector); + parcBitVector_Release(&reference); +} + +LONGBOW_TEST_CASE(Global, parcBitVector_Set) +{ + PARCBitVector *parcBitVector = parcBitVector_Create(); + assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer"); + assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_Create created a non-empty vector"); + + parcBitVector_Set(parcBitVector, 0); + assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 1, "Expect number of bits set to be 1"); + assertTrue(parcBitVector->firstBitSet == 0, "Expect first bit set to be 0"); + assertTrue(parcBitVector->bitLength == 8, "Expect the bitLength to be 8"); + assertTrue(parcBitVector->bitArray[0] == (uint8_t) 1, "Expect the bitArray as a unsigned char to be = 1"); + + parcBitVector_Set(parcBitVector, 7); + assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 2, "Expect number of bits set to be 2"); + assertTrue(parcBitVector->firstBitSet == 0, "Expect first bit set to be 0"); + assertTrue(parcBitVector->bitLength == 8, "Expect the bitLength to be 8"); + assertTrue(parcBitVector->bitArray[0] == (uint8_t) 0x81, "Expect the bitArray as a unsigned char to be = 0x81"); + + parcBitVector_Set(parcBitVector, 8); + assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 3, "Expect number of bits set to be 3"); + assertTrue(parcBitVector->firstBitSet == 0, "Expect first bit set to be 0"); + assertTrue(parcBitVector->bitLength == 16, "Expect the bitLength to be 16"); + assertTrue(parcBitVector->bitArray[0] == (uint8_t) 0x81, "Expect the bitArray as a unsigned char to be = 0x81"); + assertTrue(parcBitVector->bitArray[1] == (uint8_t) 0x1, "Expect the bitArray as a unsigned char to be = 0x1"); + + parcBitVector_Release(&parcBitVector); +} + +LONGBOW_TEST_CASE(Global, parcBitVector_And) +{ + PARCBitVector *vector1 = parcBitVector_Create(); + PARCBitVector *vector2 = parcBitVector_Create(); + + parcBitVector_Set(vector1, 1); + parcBitVector_Set(vector1, 2); + parcBitVector_Set(vector1, 10); + parcBitVector_Set(vector2, 2); + parcBitVector_Set(vector2, 1); + parcBitVector_Set(vector2, 20); + + PARCBitVector *result = parcBitVector_And(vector1, vector2); + + assertTrue(parcBitVector_NumberOfBitsSet(result) == 2, "AND vector not equal to expected results"); + parcBitVector_Release(&result); + + result = parcBitVector_And(vector1, NULL); + assertTrue(parcBitVector_NumberOfBitsSet(result) == 0, "AND vector not equal to expected results"); + parcBitVector_Release(&result); + + result = parcBitVector_And(NULL, vector2); + assertTrue(parcBitVector_NumberOfBitsSet(result) == 0, "AND vector not equal to expected results"); + parcBitVector_Release(&result); + + result = parcBitVector_And(NULL, NULL); + assertTrue(parcBitVector_NumberOfBitsSet(result) == 0, "AND vector not equal to expected results"); + parcBitVector_Release(&result); + + parcBitVector_Release(&vector1); + parcBitVector_Release(&vector2); +} + +LONGBOW_TEST_CASE(Global, parcBitVector_Or) +{ + PARCBitVector *vector1 = parcBitVector_Create(); + PARCBitVector *vector2 = parcBitVector_Create(); + + parcBitVector_Set(vector1, 1); + parcBitVector_Set(vector1, 2); + parcBitVector_Set(vector1, 10); + parcBitVector_Set(vector2, 2); + parcBitVector_Set(vector2, 1); + parcBitVector_Set(vector2, 20); + + PARCBitVector *result = parcBitVector_Or(vector1, vector2); + + assertTrue(parcBitVector_Contains(result, vector1), "Vector contents not included in OR operation results"); + assertTrue(parcBitVector_Contains(result, vector2), "Vector contents not included in OR operation results"); + assertTrue(parcBitVector_NumberOfBitsSet(result) == 4, "OR vector not equal to expected results"); + parcBitVector_Release(&result); + + result = parcBitVector_Or(vector1, NULL); + assertTrue(parcBitVector_Equals(result, vector1), "OR vector not equal to expected results"); + parcBitVector_Release(&result); + + result = parcBitVector_Or(NULL, vector2); + assertTrue(parcBitVector_Equals(result, vector2), "OR vector not equal to expected results"); + parcBitVector_Release(&result); + + result = parcBitVector_Or(NULL, NULL); + assertTrue(parcBitVector_NumberOfBitsSet(result) == 0, "OR vector not equal to expected results"); + parcBitVector_Release(&result); + + parcBitVector_Release(&vector1); + parcBitVector_Release(&vector2); +} + +LONGBOW_TEST_CASE(Global, parcBitVector_Shift) +{ + PARCBitVector *vector = parcBitVector_Create(); + + parcBitVector_Set(vector, 0); // should drop off on left shift + parcBitVector_Set(vector, 11); + parcBitVector_Set(vector, 12); + parcBitVector_Set(vector, 13); + parcBitVector_Set(vector, 22); + parcBitVector_LeftShift(vector, 10); + parcBitVector_RightShift(vector, 10); + assertTrue(parcBitVector_NextBitSet(vector, 0) == 11, "Shift operations failed"); + assertTrue(parcBitVector_NextBitSet(vector, 12) == 12, "Shift operations failed"); + assertTrue(parcBitVector_NextBitSet(vector, 14) == 22, "Shift operations failed"); + assertTrue(parcBitVector_NumberOfBitsSet(vector) == 4, "Shift operations failed to drop first bit on left shift"); + parcBitVector_Release(&vector); +} + +LONGBOW_TEST_CASE(Global, parcBitVector_SetClear) +{ + PARCBitVector *parcBitVector = parcBitVector_Create(); + assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer"); + assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_Create created a non-empty vector"); + + parcBitVector_Set(parcBitVector, 10); + assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 1, "parcBitVector_Set failed"); + + parcBitVector_Clear(parcBitVector, 10); + assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_Clear failed"); + + parcBitVector_Clear(parcBitVector, 20); + assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_Clear failed"); + + parcBitVector_Release(&parcBitVector); +} + +LONGBOW_TEST_CASE(Global, parcBitVector_SetVector) +{ + PARCBitVector *parcBitVector = parcBitVector_Create(); + assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer"); + PARCBitVector *setVector = parcBitVector_Create(); + parcBitVector_Set(parcBitVector, 1); + assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 1, "parcBitVector_Set failed"); + + parcBitVector_Set(setVector, 20); + parcBitVector_SetVector(parcBitVector, setVector); + assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 2, "parcBitVector_SetVector failed"); + assertTrue(parcBitVector_NextBitSet(parcBitVector, 0) == 1, "parcBitVector_Set failed to set bit 1"); + assertTrue(parcBitVector_NextBitSet(parcBitVector, 2) == 20, "parcBitVector_SetVector failed to set bit 20"); + + parcBitVector_Set(setVector, 10); + parcBitVector_SetVector(parcBitVector, setVector); + assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 3, "parcBitVector_SetVector failed"); + parcBitVector_Release(&parcBitVector); + parcBitVector_Release(&setVector); +} + +LONGBOW_TEST_CASE(Global, parcBitVector_Reset) +{ + PARCBitVector *parcBitVector = parcBitVector_Create(); + assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer"); + + // Reset and empty vector test + parcBitVector_Reset(parcBitVector); + assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_Reset failed"); + + parcBitVector_Set(parcBitVector, 1); + parcBitVector_Set(parcBitVector, 42); + assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 2, "parcBitVector_Set failed"); + assertTrue(parcBitVector->bitLength == 48, "Expected a bitLength of 48"); + + parcBitVector_Reset(parcBitVector); + assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_Reset failed"); + assertTrue(parcBitVector->bitLength == 48, "Expected a bitLength of 48"); + + parcBitVector_Release(&parcBitVector); +} + +LONGBOW_TEST_CASE(Global, parcBitVector_ClearVector) +{ + PARCBitVector *parcBitVector = parcBitVector_Create(); + assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer"); + + PARCBitVector *setVector = parcBitVector_Create(); + parcBitVector_Set(parcBitVector, 1); + assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 1, "parcBitVector_Set failed to set bit"); + + parcBitVector_Set(setVector, 1); + parcBitVector_Set(setVector, 20); + parcBitVector_ClearVector(parcBitVector, setVector); + assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_ClearVector failed to clear vector"); + + parcBitVector_Set(parcBitVector, 12); + parcBitVector_Set(parcBitVector, 17); + parcBitVector_ClearVector(parcBitVector, parcBitVector); + assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_ClearVector failed to clear vector"); + + parcBitVector_Release(&parcBitVector); + parcBitVector_Release(&setVector); +} + +LONGBOW_TEST_CASE(Global, parcBitVector_NextBitSet) +{ + PARCBitVector *parcBitVector = parcBitVector_Create(); + assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer"); + assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_Create created a non-empty vector"); + + int nextBit = parcBitVector_NextBitSet(parcBitVector, 0); + assertTrue(nextBit == -1, "parcBitVector_NextBitSet should have failed (%d)", nextBit); + + parcBitVector_Set(parcBitVector, 10); + nextBit = parcBitVector_NextBitSet(parcBitVector, 0); + assertTrue(nextBit == 10, "parcBitVector_NextBitSet failed (%d)", nextBit); + + nextBit = parcBitVector_NextBitSet(parcBitVector, 20); + assertTrue(nextBit == -1, "parcBitVector_NextBitSet read past end of vector (%d)", nextBit); + + nextBit = parcBitVector_NextBitSet(parcBitVector, 10); + assertTrue(nextBit == 10, "parcBitVector_NextBitSet failed (%d)", nextBit); + + nextBit = parcBitVector_NextBitSet(parcBitVector, 11); + assertTrue(nextBit == -1, "parcBitVector_NextBitSet should have failed (%d)", nextBit); + + parcBitVector_Set(parcBitVector, 20); + nextBit = parcBitVector_NextBitSet(parcBitVector, 11); + assertTrue(nextBit == 20, "parcBitVector_NextBitSet failed (%d)", nextBit); + parcBitVector_Release(&parcBitVector); +} + +LONGBOW_TEST_CASE(Global, parcBitVector_Get) +{ + PARCBitVector *parcBitVector = parcBitVector_Create(); + assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer"); + assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_Create created a non-empty vector"); + + parcBitVector_Set(parcBitVector, 10); + int bitValue = parcBitVector_Get(parcBitVector, 10); + assertTrue(bitValue == 1, "parcBitVector_Get returned wrong value (%d)", bitValue); + + bitValue = parcBitVector_Get(parcBitVector, 11); + assertTrue(bitValue == 0, "parcBitVector_Get returned wrong value (%d)", bitValue); + + bitValue = parcBitVector_Get(parcBitVector, 100); + assertTrue(bitValue == -1, "parcBitVector_NextBitSet should have failed (%d)", bitValue); + + parcBitVector_Release(&parcBitVector); +} + +LONGBOW_TEST_CASE(Global, parcBitVector_ToString) +{ + PARCBitVector *parcBitVector = parcBitVector_Create(); + assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer"); + + char *string = parcBitVector_ToString(parcBitVector); + assertTrue(strcmp(string, "[ ]") == 0, "parcBitVector_ToString returned unexpected representation (%s != [ ])", string); + parcMemory_Deallocate(&string); + + parcBitVector_Set(parcBitVector, 10); + parcBitVector_Set(parcBitVector, 1); + string = parcBitVector_ToString(parcBitVector); + assertTrue(strcmp(string, "[ 1 10 ]") == 0, "parcBitVector_ToString returned unexpected representation (%s != [ 1 10 ])", string); + parcMemory_Deallocate(&string); + + parcBitVector_Release(&parcBitVector); +} + +LONGBOW_TEST_CASE(Global, parcBitVector_Copy) +{ + PARCBitVector *parcBitVector = parcBitVector_Create(); + assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer"); + + parcBitVector_Set(parcBitVector, 10); + PARCBitVector *copy = parcBitVector_Copy(parcBitVector); + assertTrue(parcBitVector_NumberOfBitsSet(copy) == 1, "parcBitVector_Copy failed to copy set bit"); + assertTrue(parcBitVector_NextBitSet(copy, 0) == 10, "parcBitVector_Copy failed to copy correct bit"); + + parcBitVector_Release(©); + parcBitVector_Release(&parcBitVector); +} + +LONGBOW_TEST_CASE(Global, parcBitVector_Equals) +{ + PARCBitVector *parcBitVector = parcBitVector_Create(); + assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer"); + + parcBitVector_Set(parcBitVector, 10); + PARCBitVector *copy = parcBitVector_Copy(parcBitVector); + assertTrue(parcBitVector_Equals(parcBitVector, copy), "Duplicate vector found unequal"); + + parcBitVector_Set(copy, 9); + assertFalse(parcBitVector_Equals(parcBitVector, copy), "Unequal vector found equal"); + + parcBitVector_Clear(copy, 9); + parcBitVector_Set(copy, 29); + assertFalse(parcBitVector_Equals(parcBitVector, copy), "Unequal long vector found equal"); + + parcBitVector_Clear(copy, 29); + assertTrue(parcBitVector_Equals(parcBitVector, copy), "Equal long vector found unequal"); + assertTrue(parcBitVector_Equals(copy, parcBitVector), "Equal long vector found unequal"); + + parcBitVector_Release(©); + parcBitVector_Release(&parcBitVector); +} + +LONGBOW_TEST_CASE(Global, parcBitVector_Contains) +{ + PARCBitVector *supersetVector = parcBitVector_Create(); + + parcBitVector_Set(supersetVector, 10); + parcBitVector_Set(supersetVector, 11); + + PARCBitVector *testVector = parcBitVector_Create(); + parcBitVector_Set(testVector, 10); + assertTrue(parcBitVector_Contains(supersetVector, testVector), "Expect superset to contain testVector"); + + parcBitVector_Set(testVector, 12); + assertFalse(parcBitVector_Contains(supersetVector, testVector), "Expect superset to not contain testVector"); + + parcBitVector_Release(&supersetVector); + parcBitVector_Release(&testVector); +} + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks %d memory 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(parc_BitVector); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_Buffer.c b/libparc/parc/algol/test/test_parc_Buffer.c new file mode 100644 index 00000000..99b3bfd6 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_Buffer.c @@ -0,0 +1,1502 @@ +/* + * 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 <inttypes.h> +#include <stdio.h> +#include <inttypes.h> + +#include <LongBow/unit-test.h> +#include <LongBow/debugging.h> +#include <parc/algol/parc_SafeMemory.h> +#include <parc/testing/parc_ObjectTesting.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../parc_Buffer.c" + +LONGBOW_TEST_RUNNER(parcBuffer) +{ + // 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(CreateDestroy); + LONGBOW_RUN_TEST_FIXTURE(Static); + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(GettersSetters); + LONGBOW_RUN_TEST_FIXTURE(CreateDestroyErrors); + LONGBOW_RUN_TEST_FIXTURE(Errors); + LONGBOW_RUN_TEST_FIXTURE(Performance); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parcBuffer) +{ + 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(parcBuffer) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(CreateDestroy) +{ + LONGBOW_RUN_TEST_CASE(CreateDestroy, parcBuffer_Allocate); + LONGBOW_RUN_TEST_CASE(CreateDestroy, parcBuffer_Allocate_0); + LONGBOW_RUN_TEST_CASE(CreateDestroy, parcBuffer_Allocate_AcquireRelease); + LONGBOW_RUN_TEST_CASE(CreateDestroy, parcBuffer_Allocate_SIZE_MAX); + LONGBOW_RUN_TEST_CASE(CreateDestroy, parcBuffer_Wrap); + LONGBOW_RUN_TEST_CASE(CreateDestroy, parcBuffer_Wrap_NULL); + LONGBOW_RUN_TEST_CASE(CreateDestroy, parcBuffer_Wrap_WithOffset); + LONGBOW_RUN_TEST_CASE(CreateDestroy, parcBuffer_AllocateCString); +} + +LONGBOW_TEST_FIXTURE_SETUP(CreateDestroy) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(CreateDestroy) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(CreateDestroy, parcBuffer_Allocate) +{ + PARCBuffer *actual = parcBuffer_Allocate(10); + assertTrue(parcBuffer_Position(actual) == 0, "Expected initial position to be 0."); + assertTrue(parcBuffer_Limit(actual) == 10, "Expected initial limit to be 10."); + assertTrue(_markIsDiscarded(actual), "Expected initial mark to be discarded."); + + parcBuffer_Release(&actual); +} + +LONGBOW_TEST_CASE(CreateDestroy, parcBuffer_Allocate_0) +{ + PARCBuffer *actual = parcBuffer_Allocate(0); + assertTrue(parcBuffer_Position(actual) == 0, "Expected initial position to be 0."); + assertTrue(parcBuffer_Limit(actual) == 0, "Expected initial limit to be 10."); + assertTrue(_markIsDiscarded(actual), "Expected initial mark to be discarded."); + + parcBuffer_Release(&actual); +} + +LONGBOW_TEST_CASE(CreateDestroy, parcBuffer_Allocate_SIZE_MAX) +{ + PARCBuffer *actual = parcBuffer_Allocate(SIZE_MAX); + assertNull(actual, "Expected parcBuffer_Allocate to return NULL"); +} + +LONGBOW_TEST_CASE(CreateDestroy, parcBuffer_Wrap_NULL) +{ + PARCBuffer *actual = parcBuffer_Wrap(NULL, 10, 0, 10); + assertNull(actual, "Expected parcBuffer_Wrap to return NULL"); +} + +LONGBOW_TEST_CASE(CreateDestroy, parcBuffer_Wrap) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *actual = parcBuffer_Wrap(array, 10, 0, 10); + assertTrue(parcBuffer_Position(actual) == 0, "Expected initial position to be 0."); + assertTrue(parcBuffer_Limit(actual) == sizeof(array) / sizeof(array[0]), "Expected initial limit to be 10."); + assertTrue(_markIsDiscarded(actual), "Expected initial mark to be discarded."); + + parcBuffer_Release(&actual); +} + +LONGBOW_TEST_CASE(CreateDestroy, parcBuffer_Wrap_WithOffset) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *actual = parcBuffer_Wrap(array, 10, 3, 10); + assertTrue(parcBuffer_Capacity(actual) == 10, "Expected initial capacity to be 3."); + assertTrue(parcBuffer_Limit(actual) == 10, "Expected initial limit to be 3."); + assertTrue(parcBuffer_Position(actual) == 3, "Expected initial position to be 0."); + assertTrue(_markIsDiscarded(actual), "Expected initial mark to be discarded."); + + parcBuffer_Release(&actual); +} + +LONGBOW_TEST_CASE(CreateDestroy, parcBuffer_AllocateCString) +{ + PARCBuffer *buffer = parcBuffer_AllocateCString("Hello World"); + assertNotNull(buffer, "Expected parcBuffer_AllocateCString to return non-null value"); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(CreateDestroy, parcBuffer_Allocate_AcquireRelease) +{ + PARCBuffer *expected = parcBuffer_Allocate(10); + PARCBuffer *actual = parcBuffer_Acquire(expected); + + assertTrue(expected == actual, "Expected %p, actual %p", (void *) expected, (void *) actual); + + parcBuffer_Release(&expected); + assertTrue(expected == NULL, "Expected parcBuffer_Release to NULL the pointer."); + parcBuffer_Release(&actual); + assertTrue(actual == NULL, "Expected parcBuffer_Release to NULL the pointer."); +} + +LONGBOW_TEST_FIXTURE(CreateDestroyErrors) +{ + LONGBOW_RUN_TEST_CASE(CreateDestroyErrors, parcBuffer_Allocate_AcquireRelease_TooMany); + LONGBOW_RUN_TEST_CASE(CreateDestroyErrors, parcBuffer_WrapByteArray_limit_exceeds_capacity); +} + +LONGBOW_TEST_FIXTURE_SETUP(CreateDestroyErrors) +{ + PARCByteArray *array = parcByteArray_Allocate(10); + longBowTestCase_SetClipBoardData(testCase, array); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(CreateDestroyErrors) +{ + PARCByteArray *array = longBowTestCase_GetClipBoardData(testCase); + parcByteArray_Release(&array); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE_EXPECTS(CreateDestroyErrors, parcBuffer_Allocate_AcquireRelease_TooMany, .event = &LongBowTrapIllegalValue) +{ + PARCBuffer *expected = parcBuffer_Allocate(10); + PARCBuffer *actual = parcBuffer_Acquire(expected); + PARCBuffer *alias = actual; + + parcBuffer_Release(&expected); + parcBuffer_Release(&actual); + parcBuffer_Release(&alias); // this must fail. +} + +LONGBOW_TEST_CASE_EXPECTS(CreateDestroyErrors, parcBuffer_WrapByteArray_limit_exceeds_capacity, .event = &LongBowAssertEvent) +{ + PARCByteArray *array = longBowTestCase_GetClipBoardData(testCase); + + PARCBuffer *buffer = parcBuffer_WrapByteArray(array, 0, parcByteArray_Capacity(array) + 1); + + assertNotNull(buffer, "Expected NULL"); +} + +LONGBOW_TEST_FIXTURE(Global) +{ +// LONGBOW_RUN_TEST_CASE(Global, HELPME); +// LONGBOW_RUN_TEST_CASE(Global, HELPME2); + + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Array); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_ArrayOffset); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Clear); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Clone); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Duplicate); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Clone_WithOffset); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Compare); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Equals); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Equals_ZeroLength); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Equals_Bug80); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Flip); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_GetByte); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_GetBytes); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_GetBytes_Incremental); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_HasRemaining); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_HashCode); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_HashCode_ZeroRemaining); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Mark); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Resize_Growing); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Resize_Growing_AtLimit); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Resize_Shrinking); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Resize_Shrinking_AtLimit); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Resize_Example); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Resize_Slice); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Overlay); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Position); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_PutBuffer); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_PutBuffer_ZeroLength_operand); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_PutByte); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_PutBytes); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_PutIndex); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_PutUint16); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_PutCString); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Remaining); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Rewind); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_SetLimit); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_SetLimit_TruncatePosition); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_SetPosition); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Slice); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_ToString); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_ToString_ZeroRemaining); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_SkipOver); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_SkipOver_NotFound); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_SkipTo_NotFound); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_SkipTo); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_FindUint8); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_FindUint8_NotFound); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_IsValid_True); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_ParseNumeric_Decimal); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_ParseNumeric_Hexadecimal); + + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_ParseHexString); + LONGBOW_RUN_TEST_CASE(Global, parcBuffer_CreateFromArray); +} + +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) { + 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, HELPME) +{ + uint8_t decodeBytes[] = { 0x00, 0x02, 0x00, 0x0A, 'b', 'r', 'a', 'n', 'd', 'y', 'w', 'i', 'n', 'e' }; + PARCBuffer *b1 = parcBuffer_Wrap(decodeBytes, sizeof(decodeBytes), 0, sizeof(decodeBytes)); + + // b1 is a buffer wrapping a byte array. + // This will take 2 allocations: 1 for the buffer and 1 for the wrapper around the byte array. + + PARCBuffer *s2 = parcBuffer_Slice(b1); + + // s2 is another buffer referencing the wrapper created in the original buffer. + // This will increase the allocations by 1 for the buffer making it 3. + + // **** DO NOT RELEASE s2 + + parcBuffer_Release(&b1); + // This releases the b1 buffer, deallocating it. The wrapper around the original byte array still has a reference to it from s2. + // The number of allocations is reduced by 1, making it 2 (1 for s2, and 1 for the wrapper it references) + + assertTrue(parcMemory_Outstanding() == 2, "memory imbalance"); + + parcBuffer_Release(&s2); + + assertTrue(parcMemory_Outstanding() == 0, "memory imbalance must be 0, actual %d", parcMemory_Outstanding()); +} + +LONGBOW_TEST_CASE(Global, HELPME2) +{ + uint8_t decodeBytes[] = { 0x00, 0x02, 0x00, 0x0A, 'b', 'r', 'a', 'n', 'd', 'y', 'w', 'i', 'n', 'e' }; + PARCBuffer *b1 = parcBuffer_Allocate(sizeof(decodeBytes)); + // This will create a buffer, a wrapper, and an allocated array of bytes to wrap. + // The number of allocations is 3. + + parcBuffer_PutArray(b1, sizeof(decodeBytes), decodeBytes); + parcBuffer_Flip(b1); + + PARCBuffer *s2 = parcBuffer_Slice(b1); + // The number of allocations is 4. + + // **** DO NOT RELEASE s2 + + parcBuffer_Release(&b1); + // The number of allocations is now 3, the slice buffer, the wrapper, and the allocated array of bytes. + + // This will now correctly assert + assertTrue(parcMemory_Outstanding() == 3, "memory imbalance"); + + parcBuffer_Release(&s2); + assertTrue(parcMemory_Outstanding() == 0, "memory imbalance"); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_Equals) +{ + PARCBuffer *x = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10); + PARCBuffer *y = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10); + PARCBuffer *z = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10); + + // _Pragma("GCC diagnostic push") + // _Pragma("GCC diagnostic ignored \"-Wzero-length-array\"") + // _Pragma("GCC diagnostic ignored \"-Wgnu-empty-initializer\"") + struct hack { + uint8_t dummy; + uint8_t empty[]; + }; + struct hack h = { 0 }; + PARCBuffer *u0 = parcBuffer_Wrap(h.empty, 0, 0, 0); + // _Pragma("GCC diagnostic pop") + + PARCBuffer *u1 = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10 }, 10, 0, 10); + PARCBuffer *u2 = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 9, 0, 9); + PARCBuffer *u3 = parcBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 9, 0, 9); + PARCBuffer *u4 = parcBuffer_SetPosition(parcBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 9, 0, 9), 2); + PARCBuffer *u5 = parcBuffer_SetPosition(parcBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 9, 0, 9), 9); + PARCBuffer *u6 = parcBuffer_SetPosition(parcBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 9, 0, 9), 9); + PARCBuffer *u7 = parcBuffer_Wrap((uint8_t [9]) { 0 }, 0, 0, 0); + + parcObjectTesting_AssertEqualsFunction(parcBuffer_Equals, x, y, z, u0, u1, u2, u3, u4, u5, u6, u7, NULL); + + parcBuffer_Release(&x); + parcBuffer_Release(&y); + parcBuffer_Release(&z); + parcBuffer_Release(&u0); + parcBuffer_Release(&u1); + parcBuffer_Release(&u2); + parcBuffer_Release(&u3); + parcBuffer_Release(&u4); + parcBuffer_Release(&u5); + parcBuffer_Release(&u6); + parcBuffer_Release(&u7); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_Equals_ZeroLength) +{ + // _Pragma("GCC diagnostic push") + // _Pragma("GCC diagnostic ignored \"-Wzero-length-array\"") + // _Pragma("GCC diagnostic ignored \"-Wgnu-empty-initializer\"") + + struct hack { + uint8_t dummy; + uint8_t empty[]; + }; + struct hack h = { 0 }; + PARCBuffer *x = parcBuffer_Wrap(h.empty, 0, 0, 0); + PARCBuffer *y = parcBuffer_Wrap(h.empty, 0, 0, 0); + PARCBuffer *z = parcBuffer_Wrap(h.empty, 0, 0, 0); + + // _Pragma("GCC diagnostic pop") + + PARCBuffer *u1 = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10 }, 10, 0, 10); + PARCBuffer *u2 = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 9, 0, 9); + + parcObjectTesting_AssertEqualsFunction(parcBuffer_Equals, x, y, z, u1, u2, NULL); + + parcBuffer_Release(&x); + parcBuffer_Release(&y); + parcBuffer_Release(&z); + parcBuffer_Release(&u1); + parcBuffer_Release(&u2); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_Equals_Bug80) +{ + PARCBuffer *x = parcBuffer_WrapCString("a"); + PARCBuffer *y = parcBuffer_WrapCString("a"); + PARCBuffer *z = parcBuffer_WrapCString("a"); + PARCBuffer *u1 = parcBuffer_WrapCString("b"); + PARCBuffer *u2 = parcBuffer_WrapCString(""); + PARCBuffer *u3 = parcBuffer_WrapCString("ab"); + + parcObjectTesting_AssertEqualsFunction(parcBuffer_Equals, x, y, z, u1, u2, u3); + + parcBuffer_Release(&x); + parcBuffer_Release(&y); + parcBuffer_Release(&z); + parcBuffer_Release(&u1); + parcBuffer_Release(&u2); + parcBuffer_Release(&u3); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_Compare) +{ + PARCBuffer *x = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10); + PARCBuffer *y = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10); + + PARCBuffer *equivalent[] = { + x, + y, + NULL + }; + PARCBuffer *lesser[] = { + parcBuffer_Wrap((uint8_t [9]) { 0 }, 0, 0, 0), + parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8}, 10, 0, 10), + parcBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 5, 7, 8,}, 9, 0, 9), + NULL + }; + PARCBuffer *greater[] = { + parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10 }, 10, 0, 10), + parcBuffer_Wrap((uint8_t [11]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 11, 0, 11), + NULL + }; + + parcObjectTesting_AssertCompareTo(parcBuffer_Compare, x, equivalent, lesser, greater); + + parcBuffer_Release(&x); + parcBuffer_Release(&y); + + for (int i = 0; lesser[i] != NULL; i++) { + parcBuffer_Release(&lesser[i]); + } + for (int i = 0; greater[i] != NULL; i++) { + parcBuffer_Release(&greater[i]); + } +} + +LONGBOW_TEST_CASE(Global, parcBuffer_Array) +{ + uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *buffer = parcBuffer_Wrap(expected, 10, 0, 10); + + PARCByteArray *array = parcBuffer_Array(buffer); + uint8_t *actual = parcByteArray_Array(array); + + parcBuffer_Release(&buffer); + + assertTrue(expected == actual, + "Expected %p, actual %p", (void *) expected, (void *) actual); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_Resize_Growing) +{ + uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + PARCBuffer *buffer = parcBuffer_Allocate(12); + parcBuffer_PutArray(buffer, sizeof(expected), expected); + + parcBuffer_SetPosition(buffer, 5); + parcBuffer_SetLimit(buffer, 11); + parcBuffer_Mark(buffer); + + parcBuffer_Resize(buffer, 20); + + assertTrue(buffer->position == 5, "Expected position at %d, actual %zd", 5, buffer->position); + assertTrue(buffer->mark == 5, "Expected mark at %d, actual %zd", 5, buffer->mark); + assertTrue(buffer->limit == 11, "Expected limit at %d, actual %zd", 11, buffer->limit); + assertTrue(parcBuffer_Capacity(buffer) == 20, "Expected capacity at %d, actual %zd", 20, parcBuffer_Capacity(buffer)); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_Resize_Growing_AtLimit) +{ + uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + PARCBuffer *buffer = parcBuffer_Allocate(12); + parcBuffer_PutArray(buffer, sizeof(expected), expected); + + parcBuffer_SetPosition(buffer, 5); + parcBuffer_Mark(buffer); + + parcBuffer_Resize(buffer, 20); + + assertTrue(buffer->position == 5, "Expected position at %d, actual %zd", 5, buffer->position); + assertTrue(buffer->mark == 5, "Expected mark at %d, actual %zd", 5, buffer->mark); + assertTrue(buffer->limit == 20, "Expected limit at %d, actual %zd", 20, buffer->limit); + assertTrue(parcBuffer_Capacity(buffer) == 20, "Expected capacity at %d, actual %zd", 20, parcBuffer_Capacity(buffer)); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_Resize_Shrinking) +{ + uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + PARCBuffer *buffer = parcBuffer_Allocate(10); + parcBuffer_PutArray(buffer, sizeof(expected), expected); + + parcBuffer_SetPosition(buffer, 3); + parcBuffer_SetLimit(buffer, 4); + parcBuffer_Mark(buffer); + + parcBuffer_Resize(buffer, 5); + + assertTrue(buffer->position == 3, "Expected position at %d, actual %zd", 3, buffer->position); + assertTrue(buffer->mark == 3, "Expected mark to be 3"); + assertTrue(buffer->limit == 4, "Expected limit at %d, actual %zd", 4, buffer->limit); + assertTrue(parcBuffer_Capacity(buffer) == 5, "Expected capacity at %d, actual %zd", 5, parcBuffer_Capacity(buffer)); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_Resize_Shrinking_AtLimit) +{ + uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + PARCBuffer *buffer = parcBuffer_Allocate(10); + parcBuffer_PutArray(buffer, sizeof(expected), expected); + + parcBuffer_SetPosition(buffer, 5); + parcBuffer_SetLimit(buffer, 5); + parcBuffer_Mark(buffer); + + parcBuffer_Resize(buffer, 3); + + assertTrue(buffer->position == 3, "Expected position at %d, actual %zd", 3, buffer->position); + assertTrue(_markIsDiscarded(buffer), "Expected mark to be discarded"); + assertTrue(buffer->limit == 3, "Expected limit at %d, actual %zd", 3, buffer->limit); + assertTrue(parcBuffer_Capacity(buffer) == 3, "Expected capacity at %d, actual %zd", 3, parcBuffer_Capacity(buffer)); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_Resize_Example) +{ + PARCBuffer *buffer = parcBuffer_WrapCString("Hello World"); + parcBuffer_Resize(buffer, 4); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_Resize_Slice) +{ + PARCBuffer *buffer = parcBuffer_WrapCString("Hello World"); + parcBuffer_SetPosition(buffer, 5); + PARCBuffer *slice = parcBuffer_Slice(buffer); + + parcBuffer_Resize(slice, 4); + + parcBuffer_Release(&buffer); + parcBuffer_Release(&slice); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_Flip) +{ + uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *buffer = parcBuffer_Allocate(10); + parcBuffer_PutArray(buffer, 10, expected); + parcBuffer_Flip(buffer); + assertTrue(parcBuffer_Position(buffer) == 0, "Expected position to be 0."); + assertTrue(parcBuffer_Limit(buffer) == 10, "Expected limit to be 10."); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_Clear) +{ + uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *buffer = parcBuffer_Allocate(10); + parcBuffer_PutArray(buffer, 10, expected); + parcBuffer_Clear(buffer); + assertTrue(parcBuffer_Position(buffer) == 0, "Expected position to be 0."); + assertTrue(parcBuffer_Limit(buffer) == 10, "Expected limit to be 10."); + assertTrue(buffer->mark >= parcBuffer_Capacity(buffer), "Expected the mark to be unset."); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_ArrayOffset) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + size_t expected = 5; + PARCBuffer *buffer = parcBuffer_Wrap(array, 10, expected, 10); + + size_t actual = parcBuffer_ArrayOffset(buffer); + parcBuffer_Release(&buffer); + + assertTrue(0 == actual, + "Expected offset to be 0, actual %zd", actual); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_Position) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10); + + size_t expected = 5; + parcBuffer_SetPosition(buffer, expected); + + size_t actual = parcBuffer_Position(buffer); + + assertTrue(expected == actual, + "Expected position to be 0, actual %zd", actual); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_Overlay) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + uint8_t expected[5] = { 5, 6, 7, 8, 9 }; + + PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10); + + size_t position = 5; + parcBuffer_SetPosition(buffer, position); + uint8_t *actual = parcBuffer_Overlay(buffer, sizeof(array) - position); + + assertTrue(memcmp(expected, actual, sizeof(expected)) == 0, + "Array contents should not be different."); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_Clone) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *original = parcBuffer_Wrap(array, 10, 0, 10); + + PARCBuffer *clone = parcBuffer_Copy(original); + + assertTrue(clone != original, "Expected the clone to be a different instance."); + + assertTrue(parcBuffer_Equals(original, clone), "Expected clone to be equal to the original."); + + parcBuffer_Release(&original); + assertNull(original, "Expected the parcBuffer_Release function to NULL the pointer."); + + parcBuffer_Release(&clone); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_Clone_WithOffset) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *original = parcBuffer_Wrap(array, 10, 0, 10); + parcBuffer_SetLimit(original, 9); + parcBuffer_SetPosition(original, 1); + PARCBuffer *range = parcBuffer_Slice(original); + + PARCBuffer *clone = parcBuffer_Copy(range); + + assertTrue(clone != original, "Expected the clone to be a different instance."); + + assertTrue(parcBuffer_Equals(range, clone), "Expected clone to be equal to the original."); + + parcBuffer_Release(&clone); + parcBuffer_Release(&range); + parcBuffer_Release(&original); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_SetPosition) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10); + + size_t expected = 2; + parcBuffer_SetPosition(buffer, expected); + size_t actual = parcBuffer_Position(buffer); + + assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_SetLimit) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10); + + size_t expected = 2; + parcBuffer_SetLimit(buffer, expected); + size_t actual = parcBuffer_Limit(buffer); + + assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_SetLimit_TruncatePosition) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10); + + parcBuffer_SetPosition(buffer, 5); + parcBuffer_Mark(buffer); + + size_t expected = 2; + parcBuffer_SetLimit(buffer, expected); + size_t actual = parcBuffer_Limit(buffer); + + assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_Slice) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10); + parcBuffer_GetUint8(buffer); + + PARCBuffer *actual = parcBuffer_Slice(buffer); + assertTrue(parcBuffer_Position(actual) == 0, + "Expected position to be 0"); + assertTrue(parcBuffer_Limit(actual) == parcBuffer_Remaining(buffer), + "Expected position to be %zd", parcBuffer_Remaining(buffer)); + assertTrue(_markIsDiscarded(actual), "Expected the mark to be discarded."); + + parcBuffer_Release(&buffer); + parcBuffer_Release(&actual); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_Remaining) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10); + + size_t expected = 2; + parcBuffer_SetLimit(buffer, expected); + size_t actual = parcBuffer_Limit(buffer); + + assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_HasRemaining) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10); + bool actual = parcBuffer_HasRemaining(buffer); + + assertTrue(actual, "Expected true"); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_Rewind) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10); + parcBuffer_SetPosition(buffer, 4); + size_t actual = parcBuffer_Position(buffer); + assertTrue(actual == 4, "Expected position to be at 4."); + + parcBuffer_Rewind(buffer); + + actual = parcBuffer_Position(buffer); + assertTrue(actual == 0, "Expected position to be at 0."); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_Duplicate) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10); + parcBuffer_SetPosition(buffer, 4); + + PARCBuffer *buffer2 = parcBuffer_Duplicate(buffer); + + assertTrue(buffer != buffer2, "Expected distinct pointers to the different buffers."); + assertTrue(parcBuffer_Position(buffer) == parcBuffer_Position(buffer2), "Expected equal position values."); + assertTrue(parcBuffer_Limit(buffer) == parcBuffer_Limit(buffer2), "Expected equal limit values."); + assertTrue(parcBuffer_Capacity(buffer) == parcBuffer_Capacity(buffer2), "Expected equal capacity values."); + + parcBuffer_Rewind(buffer); + assertFalse(parcBuffer_Position(buffer) == parcBuffer_Position(buffer2), "Expected unequal position values."); + + parcBuffer_Release(&buffer); + parcBuffer_Release(&buffer2); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_Mark) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10); + + size_t expected = 2; + parcBuffer_SetPosition(buffer, expected); + parcBuffer_Mark(buffer); + parcBuffer_SetPosition(buffer, 4); + parcBuffer_Reset(buffer); + size_t actual = parcBuffer_Position(buffer); + + assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_PutByte) +{ + PARCBuffer *buffer = parcBuffer_Allocate(10); + + uint8_t expectedValue = 1; + parcBuffer_PutUint8(buffer, expectedValue); + + size_t expectedPosition = 1; + size_t actualPosition = parcBuffer_Position(buffer); + + parcBuffer_SetPosition(buffer, 0); + uint8_t actualValue = parcBuffer_GetAtIndex(buffer, 0); + parcBuffer_Release(&buffer); + + assertTrue(expectedValue == actualValue, + "Expected %d, actual %d", expectedValue, actualValue); + assertTrue(expectedPosition == actualPosition, + "Expected %zu, actual %zu", expectedPosition, actualPosition); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_PutCString) +{ + PARCBuffer *buffer = parcBuffer_Allocate(10); + + char *expectedValue = "abcdefg"; + parcBuffer_PutCString(buffer, expectedValue); + + size_t expectedPosition = 8; + size_t actualPosition = parcBuffer_Position(buffer); + + uint8_t zero = parcBuffer_GetAtIndex(buffer, 7); + + assertTrue(zero == 0, "Expected zero, actual %d", zero); + + assertTrue(expectedPosition == actualPosition, + "Expected %zu, actual %zu", expectedPosition, actualPosition); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_PutUint16) +{ + PARCBuffer *buffer = parcBuffer_Allocate(10); + + uint16_t expectedValue = 0x1234; + parcBuffer_PutUint16(buffer, expectedValue); + + size_t expectedPosition = 2; + size_t actualPosition = parcBuffer_Position(buffer); + assertTrue(expectedPosition == actualPosition, + "Expected position %zd, actual %zd", expectedPosition, actualPosition); + + parcBuffer_Flip(buffer); + uint16_t actualValue = parcBuffer_GetUint16(buffer); + + actualPosition = parcBuffer_Position(buffer); + + parcBuffer_Release(&buffer); + + assertTrue(expectedValue == actualValue, + "Expected %d, actual %d", expectedValue, actualValue); + assertTrue(expectedPosition == actualPosition, + "Expected %zu, actual %zu", expectedPosition, actualPosition); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_PutIndex) +{ + PARCBuffer *buffer = parcBuffer_Allocate(10); + + uint8_t expected = 1; + parcBuffer_PutAtIndex(buffer, 0, expected); + uint8_t actual = parcBuffer_GetAtIndex(buffer, 0); + + parcBuffer_Release(&buffer); + + assertTrue(expected == actual, + "Expected %" PRIu8 ", actual %" PRIu8 "", expected, actual); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_PutBytes) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *buffer = parcBuffer_Allocate(10); + parcBuffer_PutArray(buffer, 10, array); + + size_t expected = parcBuffer_Limit(buffer); + size_t actual = parcBuffer_Position(buffer); + + assertTrue(expected == actual, "Expected position to be at the limit."); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_PutBuffer) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *buffer1 = parcBuffer_Allocate(10); + parcBuffer_PutArray(buffer1, 5, array); + + PARCBuffer *buffer2 = parcBuffer_Allocate(10); + parcBuffer_PutArray(buffer2, 5, &array[5]); + parcBuffer_Flip(buffer2); + + parcBuffer_PutBuffer(buffer1, buffer2); + + size_t expected = parcBuffer_Limit(buffer1); + size_t actual = parcBuffer_Position(buffer1); + + assertTrue(expected == actual, "Expected position to be at the limit. Expected %zd, actual %zd", expected, actual); + assertTrue(memcmp(array, parcByteArray_Array(buffer1->array), sizeof(array)) == 0, + "Array content differs."); + + parcBuffer_Release(&buffer1); + parcBuffer_Release(&buffer2); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_GetByte) +{ + uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *buffer = parcBuffer_Allocate(10); + parcBuffer_PutArray(buffer, sizeof(expected), expected); + parcBuffer_Flip(buffer); + + uint8_t actual = parcBuffer_GetUint8(buffer); + + assertTrue(expected[0] == actual, + "Expected %d, actual %d", expected[0], actual); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_GetBytes) +{ + uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + uint8_t actual[10]; + + PARCBuffer *buffer = parcBuffer_Allocate(10); + parcBuffer_PutArray(buffer, sizeof(expected), expected); + parcBuffer_Flip(buffer); + + parcBuffer_GetBytes(buffer, sizeof(actual), actual); + + assertTrue(memcmp(expected, actual, sizeof(actual)) == 0, + "Expected arrays to be equal."); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_GetBytes_Incremental) +{ + uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + uint8_t actual[10]; + + PARCBuffer *buffer = parcBuffer_Allocate(10); + parcBuffer_PutArray(buffer, sizeof(expected), expected); + parcBuffer_Flip(buffer); + + parcBuffer_GetBytes(buffer, 1, actual); + assertTrue(parcBuffer_Position(buffer) == 1, "Expected position to be %d\n", 1); + assertTrue(actual[0] == expected[0], "Expected %d, actual %d", expected[0], actual[0]); + parcBuffer_GetBytes(buffer, 1, actual); + assertTrue(parcBuffer_Position(buffer) == 2, "Expected position to be 2, actual %zd\n", parcBuffer_Position(buffer)); + assertTrue(actual[0] == expected[1], "Expected %d, actual %d", expected[1], actual[0]); + parcBuffer_GetBytes(buffer, 1, actual); + assertTrue(parcBuffer_Position(buffer) == 3, "Expected position to be 3, actual %zd\n", parcBuffer_Position(buffer)); + assertTrue(actual[0] == expected[2], "Expected %d, actual %d", expected[2], actual[0]); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_PutBuffer_ZeroLength_operand) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *buffer1 = parcBuffer_Allocate(10); + parcBuffer_PutArray(buffer1, 10, array); + + PARCBuffer *buffer2 = parcBuffer_Allocate(0); + parcBuffer_PutBuffer(buffer1, buffer2); + + size_t expected = parcBuffer_Limit(buffer1); + size_t actual = parcBuffer_Position(buffer1); + + assertTrue(expected == actual, "Expected position to be at the limit."); + + parcBuffer_Release(&buffer1); + parcBuffer_Release(&buffer2); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_HashCode) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *buffer1 = parcBuffer_Allocate(10); + parcBuffer_PutArray(buffer1, 10, array); + parcBuffer_Flip(buffer1); + + PARCBuffer *buffer2 = parcBuffer_Allocate(10); + parcBuffer_PutArray(buffer2, 10, array); + parcBuffer_Flip(buffer2); + + PARCHashCode hashX = parcBuffer_HashCode(buffer1); + PARCHashCode hashY = parcBuffer_HashCode(buffer2); + + assertTrue(hashX == hashY, "Expected %" PRIPARCHashCode ", actual %" PRIPARCHashCode, hashX, hashY); + + parcBuffer_Release(&buffer1); + parcBuffer_Release(&buffer2); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_HashCode_ZeroRemaining) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *buffer1 = parcBuffer_Allocate(10); + parcBuffer_PutArray(buffer1, 10, array); + + PARCHashCode hashX = parcBuffer_HashCode(buffer1); + + assertTrue(hashX == 0, "Expected 0, actual %" PRIPARCHashCode, hashX); + + parcBuffer_Release(&buffer1); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_ToString) +{ + uint8_t array[] = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 'x' }; + + PARCBuffer *buffer = parcBuffer_Allocate(sizeof(array) - 1); + parcBuffer_PutArray(buffer, sizeof(array) - 1, array); + parcBuffer_Flip(buffer); + + char *actual = parcBuffer_ToString(buffer); + + assertTrue(strcmp("hello world", actual) == 0, "Expected 'hello world', actual %s", actual); + + parcMemory_Deallocate((void **) &actual); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_ToString_ZeroRemaining) +{ + uint8_t array[] = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 'x' }; + + PARCBuffer *buffer = parcBuffer_Allocate(sizeof(array) - 1); + parcBuffer_PutArray(buffer, sizeof(array) - 1, array); +// parcBuffer_Flip(buffer); + + char *actual = parcBuffer_ToString(buffer); + + assertTrue(strcmp("", actual) == 0, "Expected '', actual %s", actual); + + parcMemory_Deallocate((void **) &actual); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_SkipOver) +{ + PARCBuffer *buffer = parcBuffer_WrapCString("Hello World"); + uint8_t skipOverBytes[] = { 'H', 0 }; + + bool actual = parcBuffer_SkipOver(buffer, 1, skipOverBytes); + + assertTrue(actual, "Expected parcBuffer_SkipOver to return true."); + + uint8_t peekByte = parcBuffer_PeekByte(buffer); + + assertTrue(peekByte == 'e', "Expected buffer to point to 'e', actual '%c'", peekByte); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_SkipOver_NotFound) +{ + PARCBuffer *buffer = parcBuffer_WrapCString("Hello World"); + + bool actual = parcBuffer_SkipOver(buffer, 8, (uint8_t *) "Helo Wrd"); + + assertFalse(actual, "Expected parcBuffer_SkipOver to return false."); + + assertTrue(parcBuffer_Remaining(buffer) == 0, + "Expected buffer to have no remaining bytes. Actual %zd", parcBuffer_Remaining(buffer)); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_SkipTo) +{ + PARCBuffer *buffer = parcBuffer_WrapCString("Hello World"); + uint8_t skipToBytes[] = { 'l', 0 }; + + bool actual = parcBuffer_SkipTo(buffer, 1, skipToBytes); + + assertTrue(actual, "Expected parcBuffer_SkipOver to return true."); + + uint8_t peekByte = parcBuffer_PeekByte(buffer); + + assertTrue(peekByte == 'l', "Expected buffer to point to 'l', actual '%c'", peekByte); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_SkipTo_NotFound) +{ + PARCBuffer *buffer = parcBuffer_WrapCString("Hello World"); + + bool actual = parcBuffer_SkipTo(buffer, 1, (uint8_t *) "x"); + + assertFalse(actual, "Expected parcBuffer_SkipOver to return false."); + assertTrue(parcBuffer_Remaining(buffer) == 0, + "Expected buffer to have no remaining bytes. Actual %zd", parcBuffer_Remaining(buffer)); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_FindUint8) +{ + PARCBuffer *buffer = parcBuffer_WrapCString("Hello World"); + size_t index = parcBuffer_FindUint8(buffer, 'e'); + assertTrue(index == 1, "Expected index to be 1, actual %zu", index); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_FindUint8_NotFound) +{ + PARCBuffer *buffer = parcBuffer_WrapCString("Hello World"); + size_t index = parcBuffer_FindUint8(buffer, 'z'); + assertTrue(index == SIZE_MAX, "Expected index to be SIZE_MAX, actual %zu", index); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_IsValid_True) +{ + PARCBuffer *buffer = parcBuffer_WrapCString("Hello World"); + bool actual = parcBuffer_IsValid(buffer); + assertTrue(actual, "Expected PARCBuffer to be valid"); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_ParseNumeric_Decimal) +{ + PARCBuffer *buffer = parcBuffer_WrapCString("123abc"); + + uint64_t actual = parcBuffer_ParseNumeric(buffer); + + assertTrue(actual == 123, "Expected 123, actual %" PRIu64 "", actual); + assertTrue(parcBuffer_Position(buffer) == 3, "Expected position to be 3, actual %zd", parcBuffer_Position(buffer)); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_ParseNumeric_Hexadecimal) +{ + PARCBuffer *buffer = parcBuffer_WrapCString("0x123xyz"); + + uint64_t actual = parcBuffer_ParseNumeric(buffer); + + assertTrue(actual == 0x123, "Expected 0x123, actual %" PRIx64 "", actual); + assertTrue(parcBuffer_Position(buffer) == 5, "Expected position to be 5, actual %zd", parcBuffer_Position(buffer)); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_ParseHexString) +{ + char *expected = "00"; + PARCBuffer *buffer = parcBuffer_ParseHexString("3030"); + parcBuffer_Flip(buffer); + char *actual = parcBuffer_ToString(buffer); + + assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual); + + parcMemory_Deallocate(&actual); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcBuffer_CreateFromArray) +{ + char *expected = "0123456789ABCDEF"; + PARCBuffer *buffer = parcBuffer_CreateFromArray(expected, strlen(expected)); + + assertTrue(parcBuffer_Position(buffer) == 16, "Expected position to be at 15, actual %zd", parcBuffer_Position(buffer)); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_FIXTURE(GettersSetters) +{ + LONGBOW_RUN_TEST_CASE(GettersSetters, parcPutGetUint8); + LONGBOW_RUN_TEST_CASE(GettersSetters, parcPutGetUint16); + LONGBOW_RUN_TEST_CASE(GettersSetters, parcPutGetUint32); + LONGBOW_RUN_TEST_CASE(GettersSetters, parcPutGetUint64); + LONGBOW_RUN_TEST_CASE(GettersSetters, parcBuffer_ToHexString); + LONGBOW_RUN_TEST_CASE(GettersSetters, parcBuffer_ToHexString_NULLBuffer); + LONGBOW_RUN_TEST_CASE(GettersSetters, parcBuffer_Display); + LONGBOW_RUN_TEST_CASE(GettersSetters, parcBuffer_Display_NULL); +} + +LONGBOW_TEST_FIXTURE_SETUP(GettersSetters) +{ + PARCBuffer *buffer = parcBuffer_Allocate(100); + + longBowTestCase_SetClipBoardData(testCase, buffer); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(GettersSetters) +{ + PARCBuffer *buffer = longBowTestCase_GetClipBoardData(testCase); + parcBuffer_Release(&buffer); + + 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(GettersSetters, parcPutGetUint8) +{ + PARCBuffer *buffer = longBowTestCase_GetClipBoardData(testCase); + + uint8_t expected = 0x12; + parcBuffer_PutUint8(buffer, expected); + parcBuffer_Flip(buffer); + uint8_t actual = parcBuffer_GetUint8(buffer); + + assertTrue(expected == actual, "Expected %d, actual %d", expected, actual); +} + +LONGBOW_TEST_CASE(GettersSetters, parcPutGetUint16) +{ + PARCBuffer *buffer = longBowTestCase_GetClipBoardData(testCase); + + uint16_t expected = 0x1234; + parcBuffer_PutUint16(buffer, expected); + parcBuffer_Flip(buffer); + uint16_t actual = parcBuffer_GetUint16(buffer); + + assertTrue(expected == actual, "Expected %d, actual %d", expected, actual); +} + +LONGBOW_TEST_CASE(GettersSetters, parcPutGetUint32) +{ + PARCBuffer *buffer = longBowTestCase_GetClipBoardData(testCase); + + uint32_t expected = 0x12345678; + parcBuffer_PutUint32(buffer, expected); + parcBuffer_Flip(buffer); + uint32_t actual = parcBuffer_GetUint32(buffer); + + assertTrue(expected == actual, "Expected %d, actual %d", expected, actual); +} + +LONGBOW_TEST_CASE(GettersSetters, parcPutGetUint64) +{ + PARCBuffer *buffer = longBowTestCase_GetClipBoardData(testCase); + + uint64_t expected = 0x1234567812345678; + parcBuffer_PutUint64(buffer, expected); + parcBuffer_Flip(buffer); + uint64_t actual = parcBuffer_GetUint64(buffer); + + assertTrue(expected == actual, "Expected %" PRIu64 ", actual %" PRIu64 "", expected, actual); +} + +LONGBOW_TEST_CASE(GettersSetters, parcBuffer_ToHexString) +{ + PARCBuffer *buffer = longBowTestCase_GetClipBoardData(testCase); + + uint64_t expected = 0x1234567812345678; + parcBuffer_PutUint64(buffer, expected); + parcBuffer_Flip(buffer); + char *hexString = parcBuffer_ToHexString(buffer); + + assertTrue(strcmp("1234567812345678", hexString) == 0, "Expected 1234567812345678, actual %s", hexString); + parcMemory_Deallocate((void **) &hexString); +} + +LONGBOW_TEST_CASE(GettersSetters, parcBuffer_ToHexString_NULLBuffer) +{ + char *hexString = parcBuffer_ToHexString(NULL); + + assertTrue(strcmp("null", hexString) == 0, "Expected null, actual %s", hexString); + parcMemory_Deallocate((void **) &hexString); +} + +LONGBOW_TEST_CASE(GettersSetters, parcBuffer_Display) +{ + PARCBuffer *buffer = longBowTestCase_GetClipBoardData(testCase); + + uint64_t expected = 0x1234567812345678; + parcBuffer_PutUint64(buffer, expected); + parcBuffer_Flip(buffer); + parcBuffer_Display(buffer, 0); +} + +LONGBOW_TEST_CASE(GettersSetters, parcBuffer_Display_NULL) +{ + parcBuffer_Display(NULL, 0); +} + +LONGBOW_TEST_FIXTURE(Errors) +{ + LONGBOW_RUN_TEST_CASE(Errors, parcBuffer_GetByte_Underflow); + LONGBOW_RUN_TEST_CASE(Errors, parcBuffer_Mark_mark_exceeds_position); +} + +typedef struct parc_buffer_longbow_clipboard { + PARCBuffer *buffer; +} parcBuffer_LongBowClipBoard; + +LONGBOW_TEST_FIXTURE_SETUP(Errors) +{ + parcBuffer_LongBowClipBoard *testData = calloc(1, sizeof(parcBuffer_LongBowClipBoard)); + testData->buffer = parcBuffer_Allocate(10); + + longBowTestCase_SetClipBoardData(testCase, testData); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Errors) +{ + parcBuffer_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase); + parcBuffer_Release(&testData->buffer); + free(testData); + + 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_EXPECTS(Errors, parcBuffer_GetByte_Underflow, .event = &LongBowTrapOutOfBounds) +{ + parcBuffer_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *buffer = testData->buffer; + + uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + parcBuffer_PutArray(buffer, 1, expected); + parcBuffer_Flip(buffer); + + parcBuffer_GetUint8(buffer); + parcBuffer_GetUint8(buffer); // this will fail. +} + +LONGBOW_TEST_CASE_EXPECTS(Errors, parcBuffer_Mark_mark_exceeds_position, .event = &LongBowAssertEvent) +{ + parcBuffer_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *buffer = testData->buffer; + + size_t expected = 2; + parcBuffer_SetPosition(buffer, expected); + parcBuffer_Mark(buffer); + parcBuffer_SetPosition(buffer, 0); + parcBuffer_Reset(buffer); +} + + +LONGBOW_TEST_FIXTURE(Static) +{ + LONGBOW_RUN_TEST_CASE(Static, _digittoint); +} + +LONGBOW_TEST_FIXTURE_SETUP(Static) +{ + _longBowGlobal_Global_outstanding = parcMemory_Outstanding(); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Static) +{ + LongBowStatus result = LONGBOW_STATUS_SUCCEEDED; + + size_t allocationsLeaked = parcMemory_Outstanding() - _longBowGlobal_Global_outstanding; + + if (allocationsLeaked) { + 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(Static, _digittoint) +{ + char *base10 = "0123456789"; + + for (size_t i = 0; i < strlen(base10); i++) { + int expected = (int) i; + int actual = _digittoint(base10[i]); + assertTrue(expected == actual, "Expected %d, actual %d", expected, actual); + } + + char *base16 = "0123456789abcdef"; + + for (size_t i = 0; i < strlen(base16); i++) { + int expected = (int) i; + int actual = _digittoint(base16[i]); + assertTrue(expected == actual, "Expected %d, actual %d", expected, actual); + } + + base16 = "0123456789ABCDEF"; + + for (size_t i = 0; i < strlen(base16); i++) { + int expected = (int) i; + int actual = _digittoint(base16[i]); + assertTrue(expected == actual, "Expected %d, actual %d", expected, actual); + } +} + +LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false) +{ + LONGBOW_RUN_TEST_CASE(Performance, parcBuffer_Create); +} + +LONGBOW_TEST_FIXTURE_SETUP(Performance) +{ + _longBowGlobal_Global_outstanding = parcMemory_Outstanding(); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Performance) +{ + LongBowStatus result = LONGBOW_STATUS_SUCCEEDED; + + size_t allocationsLeaked = parcMemory_Outstanding() - _longBowGlobal_Global_outstanding; + + if (allocationsLeaked) { + 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(Performance, parcBuffer_Create) +{ + for (size_t i = 0; i < 1000000; i++) { + PARCBuffer *buffer = parcBuffer_Allocate(1200); + parcBuffer_Release(&buffer); + } +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parcBuffer); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_BufferChunker.c b/libparc/parc/algol/test/test_parc_BufferChunker.c new file mode 100755 index 00000000..8f770968 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_BufferChunker.c @@ -0,0 +1,336 @@ +/* + * 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 "../parc_BufferChunker.c" + +#include <stdio.h> + +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + +LONGBOW_TEST_RUNNER(parc_BufferChunker) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_BufferChunker) +{ + 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(parc_BufferChunker) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_CreateFromBuffer); + LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ForwardIterator_Buffer); + LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ForwardIterator_BufferPartial); + LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ForwardIterator_BufferSmall); + LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ReverseIterator_Buffer); + LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ReverseIterator_BufferPartial); + LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ReverseIterator_BufferSmall); + LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_GetChunkSize); +} + +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, parc_Chunker_CreateFromBuffer) +{ + PARCBuffer *buffer = parcBuffer_Allocate(1024); + + PARCBufferChunker *chunker = parcBufferChunker_Create(buffer, 32); // each chunk is 32 bytes + assertNotNull(chunker, "Expected non-NULL Chunker"); + PARCBufferChunker *copy = parcBufferChunker_Acquire(chunker); + assertNotNull(chunker, "Expected non-NULL Chunker"); + assertNotNull(copy, "Expected non-NULL copy of Chunker"); + parcBufferChunker_Release(©); + + parcBuffer_Release(&buffer); + parcBufferChunker_Release(&chunker); +} + +LONGBOW_TEST_CASE(Global, parc_Chunker_ForwardIterator_Buffer) +{ + PARCBuffer *buffer = parcBuffer_Allocate(1024); + + for (size_t i = 0; i < 32; i++) { + for (size_t j = 0; j < 32; j++) { + parcBuffer_PutUint8(buffer, i); + } + } + parcBuffer_Flip(buffer); + + PARCBufferChunker *chunker = parcBufferChunker_Create(buffer, 32); // each chunk is 32 bytes + assertNotNull(chunker, "Expected non-NULL Chunker"); + + PARCIterator *itr = parcBufferChunker_ForwardIterator(chunker); + size_t count = 0; + while (parcIterator_HasNext(itr)) { + PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr); + + uint8_t *contents = parcBuffer_Overlay(payload, 0); + for (size_t i = 0; i < 32; i++) { + assertTrue(contents[i] == count, "Expected %zu at index %zu, got %d", count, i, contents[i]); + } + count++; + + parcBuffer_Release(&payload); + } + assertTrue(count == 32, "Expected to iterate over 32 content objects from the chunker, but for %zu", count); + parcIterator_Release(&itr); + + parcBufferChunker_Release(&chunker); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parc_Chunker_ForwardIterator_BufferPartial) +{ + // Allocate something that's not divisible by the chunk size + PARCBuffer *buffer = parcBuffer_Allocate(1030); + + for (size_t i = 0; i < 32; i++) { + for (size_t j = 0; j < 32; j++) { + parcBuffer_PutUint8(buffer, i); + } + } + + // Special 0xFF to mark the end... + for (int i = 0; i < 6; i++) { + parcBuffer_PutUint8(buffer, 0xFF); + } + + parcBuffer_Flip(buffer); + + PARCBufferChunker *chunker = parcBufferChunker_Create(buffer, 32); // each chunk is 32 bytes + assertNotNull(chunker, "Expected non-NULL Chunker"); + + PARCIterator *itr = parcBufferChunker_ForwardIterator(chunker); + size_t count = 0; + while (parcIterator_HasNext(itr)) { + PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr); + + uint8_t *contents = parcBuffer_Overlay(payload, 0); + if (count < 32) { + for (size_t i = 0; i < 32; i++) { + assertTrue(contents[i] == count, "Expected %zu at index %zu, got %d", count, i, contents[i]); + } + } else { + for (size_t i = 0; i < 6; i++) { + assertTrue(contents[i] == 0xFF, "Expected %zu at index %zu, got %d", (size_t) 0xFF, i, contents[i]); + } + } + count++; + + parcBuffer_Release(&payload); + } + assertTrue(count == 33, "Expected to iterate over 33 content objects from the chunker, but for %zu", count); + parcIterator_Release(&itr); + + parcBufferChunker_Release(&chunker); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parc_Chunker_ForwardIterator_BufferSmall) +{ + // Allocate something that's not divisible by the chunk size + PARCBuffer *buffer = parcBuffer_Allocate(16); + + // Special 0xFF to mark the end... + for (int i = 0; i < 16; i++) { + parcBuffer_PutUint8(buffer, 0xFF); + } + + parcBuffer_Flip(buffer); + + PARCBufferChunker *chunker = parcBufferChunker_Create(buffer, 32); // each chunk is 32 bytes + assertNotNull(chunker, "Expected non-NULL Chunker"); + + PARCIterator *itr = parcBufferChunker_ForwardIterator(chunker); + size_t count = 0; + while (parcIterator_HasNext(itr)) { + PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr); + + uint8_t *contents = parcBuffer_Overlay(payload, 0); + for (size_t i = 0; i < 16; i++) { + assertTrue(contents[i] == 0xFF, "Expected %zu at index %zu, got %d", (size_t) 0xFF, i, contents[i]); + } + count++; + + parcBuffer_Release(&payload); + } + assertTrue(count == 1, "Expected to iterate over 1 content objects from the chunker, but for %zu", count); + parcIterator_Release(&itr); + + parcBufferChunker_Release(&chunker); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parc_Chunker_ReverseIterator_Buffer) +{ + PARCBuffer *buffer = parcBuffer_Allocate(1024); + + for (size_t i = 0; i < 32; i++) { + for (size_t j = 0; j < 32; j++) { + parcBuffer_PutUint8(buffer, i); + } + } + parcBuffer_Flip(buffer); + + PARCBufferChunker *chunker = parcBufferChunker_Create(buffer, 32); // each chunk is 32 bytes + assertNotNull(chunker, "Expected non-NULL Chunker"); + + PARCIterator *itr = parcBufferChunker_ReverseIterator(chunker); + size_t count = 0; + while (parcIterator_HasNext(itr)) { + PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr); + + uint8_t *contents = parcBuffer_Overlay(payload, 0); + for (size_t i = 0; i < 32; i++) { + assertTrue(contents[i] == (31 - count), "Expected %zu at index %zu, got %d", (31 - count), i, contents[i]); + } + count++; + + parcBuffer_Release(&payload); + } + assertTrue(count == 32, "Expected to iterate over 32 content objects from the chunker, but for %zu", count); + parcIterator_Release(&itr); + + parcBufferChunker_Release(&chunker); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parc_Chunker_ReverseIterator_BufferPartial) +{ + PARCBuffer *buffer = parcBuffer_Allocate(1030); + + // Special 0xFF to mark the start + for (int i = 0; i < 6; i++) { + parcBuffer_PutUint8(buffer, 0xFF); + } + + for (size_t i = 0; i < 32; i++) { + for (size_t j = 0; j < 32; j++) { + parcBuffer_PutUint8(buffer, i); + } + } + parcBuffer_Flip(buffer); + + PARCBufferChunker *chunker = parcBufferChunker_Create(buffer, 32); // each chunk is 32 bytes + assertNotNull(chunker, "Expected non-NULL Chunker"); + + PARCIterator *itr = parcBufferChunker_ReverseIterator(chunker); + size_t count = 0; + while (parcIterator_HasNext(itr)) { + PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr); + + uint8_t *contents = parcBuffer_Overlay(payload, 0); + if (count < 32) { + for (size_t i = 0; i < 32; i++) { + assertTrue(contents[i] == (31 - count), "Expected %zu at index %zu, got %d", count, i, contents[i]); + } + } else { + for (size_t i = 0; i < 6; i++) { + assertTrue(contents[i] == 0xFF, "Expected %zu at index %zu, got %d", (size_t) 0xFF, i, contents[i]); + } + } + count++; + + parcBuffer_Release(&payload); + } + assertTrue(count == 33, "Expected to iterate over 33 content objects from the chunker, but for %zu", count); + parcIterator_Release(&itr); + + parcBufferChunker_Release(&chunker); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parc_Chunker_ReverseIterator_BufferSmall) +{ + PARCBuffer *buffer = parcBuffer_Allocate(16); + + // Special 0xFF to mark the start + for (int i = 0; i < 16; i++) { + parcBuffer_PutUint8(buffer, 0xFF); + } + parcBuffer_Flip(buffer); + + PARCBufferChunker *chunker = parcBufferChunker_Create(buffer, 32); // each chunk is 32 bytes + assertNotNull(chunker, "Expected non-NULL Chunker"); + + PARCIterator *itr = parcBufferChunker_ReverseIterator(chunker); + size_t count = 0; + while (parcIterator_HasNext(itr)) { + PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr); + + uint8_t *contents = parcBuffer_Overlay(payload, 0); + for (size_t i = 0; i < 16; i++) { + assertTrue(contents[i] == 0xFF, "Expected %zu at index %zu, got %d", (size_t) 0xFF, i, contents[i]); + } + count++; + + parcBuffer_Release(&payload); + } + assertTrue(count == 1, "Expected to iterate over 1 content objects from the chunker, but for %zu", count); + parcIterator_Release(&itr); + + parcBufferChunker_Release(&chunker); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parc_Chunker_GetChunkSize) +{ + size_t expectedChunkSize = 32; + PARCBuffer *buffer = parcBuffer_Allocate(16); + PARCBufferChunker *chunker = parcBufferChunker_Create(buffer, expectedChunkSize); // each chunk is 32 bytes + size_t actualChunkSize = parcBufferChunker_GetChunkSize(chunker); + + assertTrue(actualChunkSize == expectedChunkSize, "Expected chunk size of %zu, got %zu", expectedChunkSize, actualChunkSize); + + parcBuffer_Release(&buffer); + parcBufferChunker_Release(&chunker); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_BufferChunker); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_BufferComposer.c b/libparc/parc/algol/test/test_parc_BufferComposer.c new file mode 100644 index 00000000..fad9857c --- /dev/null +++ b/libparc/parc/algol/test/test_parc_BufferComposer.c @@ -0,0 +1,448 @@ +/* + * 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 "../parc_BufferComposer.c" + +#include <inttypes.h> +#include <LongBow/unit-test.h> +#include <LongBow/debugging.h> + +#include <parc/algol/parc_SafeMemory.h> +#include <parc/testing/parc_ObjectTesting.h> + +typedef struct { + uint32_t setupAllocations; + PARCBufferComposer *composer; +} TestData; + +static TestData* +commonSetup() +{ + uint32_t outstanding = parcSafeMemory_Outstanding(); + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear of %zu bytes returned NULL.", sizeof(TestData)); + data->setupAllocations = outstanding; + data->composer = parcBufferComposer_Create(); + return data; +} + +static uint32_t +commonTearDown(TestData *data) +{ + uint32_t setupAllocations = data->setupAllocations; + + // NOTE: The `parcBufferComposer_AssertValid_IncrementSize` invalidates this object, so we must + // restore it to a good state in order for all memory to be released correctly. + (data->composer)->incrementHeuristic = sizeof(void *); + + parcBufferComposer_Release(&(data->composer)); + parcMemory_Deallocate((void **) &data); + return parcSafeMemory_ReportAllocation(STDOUT_FILENO) - setupAllocations; +} + +LONGBOW_TEST_RUNNER(parc_BufferComposer) +{ + // 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(parc_BufferComposer) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_BufferComposer) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_Acquire); + LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_Allocate); + LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_Allocate_SizeMax); + LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_AssertValid); + LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_AssertValid_NULL); + LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_AssertValid_IncrementSize); + LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_Create); + LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_Equals); + LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutArray); + LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutBuffer); + LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutUint16); + LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutUint32); + LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutUint64); + LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutUint8); + LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutString); + LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutStrings); + LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_Format); + LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutChar); + LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_GetBuffer); + LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_CreateBuffer); + LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_ProduceBuffer); + LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutString_Extend); + LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_ToString); +} + +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); + + uint32_t outstandingAllocations = commonTearDown(data); + + if (outstandingAllocations != 0) { + printf("%s leaks %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, parcBufferComposer_Acquire) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + + PARCBufferComposer *handle = parcBufferComposer_Acquire(composer); + + assertNotNull(handle, "Acquired PARCBufferComposer handle should be non-NULL."); + assertTrue(parcBufferComposer_Equals(composer, handle), "PARCBufferComposer instances should be equal"); + + parcBufferComposer_Release(&handle); + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, parcBufferComposer_Allocate) +{ + size_t size = 10; + PARCBufferComposer *composer = parcBufferComposer_Allocate(size); + PARCBuffer *buffer = parcBufferComposer_GetBuffer(composer); + + assertNotNull(composer, "PARCBufferComposer instance should be non-NULL."); + assertTrue(parcBuffer_Limit(buffer) == size, + "PARCBufferComposer instance's internal PARCBuffer limit must be %zu: %zu", size, parcBuffer_Limit(buffer)); + + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, parcBufferComposer_Allocate_SizeMax) +{ + size_t size = SIZE_MAX; + PARCBufferComposer *composer = parcBufferComposer_Allocate(size); + + assertNull(composer, "PARCBufferComposer instance should be NULL."); +} + +LONGBOW_TEST_CASE(Global, parcBufferComposer_AssertValid) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + + assertNotNull(composer, "PARCBufferComposer instance should be non-NULL."); + parcBufferComposer_AssertValid(composer); + + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE_EXPECTS(Global, parcBufferComposer_AssertValid_NULL, .event = &LongBowTrapIllegalValue) +{ + parcBufferComposer_AssertValid(NULL); +} + +LONGBOW_TEST_CASE_EXPECTS(Global, parcBufferComposer_AssertValid_IncrementSize, .event = &LongBowTrapIllegalValue) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + (data->composer)->incrementHeuristic = 0; // must be >= sizeof(void *) + parcBufferComposer_AssertValid(data->composer); +} + +LONGBOW_TEST_CASE(Global, parcBufferComposer_Create) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + + assertNotNull(composer, "PARCBufferComposer instance should be non-NULL."); + + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, parcBufferComposer_Equals) +{ + PARCBufferComposer *x = parcBufferComposer_Create(); + PARCBufferComposer *y = parcBufferComposer_Create(); + PARCBufferComposer *z = parcBufferComposer_Create(); + PARCBufferComposer *u = parcBufferComposer_Allocate(10); + + parcObjectTesting_AssertEqualsFunction(parcBufferComposer_Equals, x, y, z, u); + + u->incrementHeuristic = 0; + assertFalse(parcBufferComposer_Equals(x, u), "PARCBufferComposer instances should be unequal due to size increments."); + assertFalse(parcBufferComposer_Equals(x, NULL), "Equals should return false since the second parameter is NULL."); + u->incrementHeuristic = sizeof(void *); + + parcBufferComposer_Release(&x); + parcBufferComposer_Release(&y); + parcBufferComposer_Release(&z); + parcBufferComposer_Release(&u); +} + +LONGBOW_TEST_CASE(Global, parcBufferComposer_ToString) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + parcBufferComposer_Format(composer, "hello %s", "world"); + + char *string = parcBufferComposer_ToString(composer); + + assertNotNull(string, "Expected non-NULL result from parcBufferComposer_ToString"); + + parcMemory_Deallocate((void **) &string); + + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, parcBufferComposer_GetBuffer) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + PARCBuffer *buffer = parcBufferComposer_GetBuffer(composer); + + assertNotNull(composer, "PARCBufferComposer instance should be non-NULL."); + assertNotNull(buffer, "PARCBufferComposer instance's internal PARCBuffer should not be NULL"); + + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, parcBufferComposer_PutArray) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + + uint8_t string[6] = { 'h', 'e', 'l', 'l', 'o', '\0' }; + parcBufferComposer_PutArray(composer, string, 6); + + PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer); + + char expected[5] = "hello"; + char *actual = parcBuffer_ToString(buffer); + assertTrue(strncmp(expected, actual, 5) == 0, "Expected strings to match. Got %s, expected %s", actual, expected); + + parcMemory_Deallocate((void **) &actual); + parcBuffer_Release(&buffer); + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, parcBufferComposer_PutBuffer) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + + PARCBuffer *insertee = parcBuffer_WrapCString("hello world"); + parcBufferComposer_PutBuffer(composer, insertee); + parcBuffer_Release(&insertee); + + PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer); + + char expected[11] = "hello world"; + char *actual = parcBuffer_ToString(buffer); + assertTrue(strncmp(expected, actual, 11) == 0, "Expected strings to match. Got %s, expected %s", actual, expected); + + parcMemory_Deallocate((void **) &actual); + parcBuffer_Release(&buffer); + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, parcBufferComposer_PutUint16) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + + uint16_t val = 0x0101; + parcBufferComposer_PutUint16(composer, val); + + PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer); + assertTrue(parcBuffer_GetUint16(buffer) == val, "Expected inserted uint16_t to be equal to %x, got %x", val, parcBuffer_GetUint16(buffer)); + + parcBuffer_Release(&buffer); + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, parcBufferComposer_PutUint32) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + + uint32_t val = 0x0101FFFF; + parcBufferComposer_PutUint32(composer, val); + + PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer); + assertTrue(parcBuffer_GetUint32(buffer) == val, "Expected inserted uint32_t to be equal to %x, got %x", val, parcBuffer_GetUint32(buffer)); + + parcBuffer_Release(&buffer); + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, parcBufferComposer_PutUint64) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + + uint64_t val = 0x0101FFFFABCD0123; + parcBufferComposer_PutUint64(composer, val); + + PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer); + assertTrue(parcBuffer_GetUint64(buffer) == val, + "Expected inserted uint64_t to be equal to %" PRIu64 ", got %" PRIu64 "", val, parcBuffer_GetUint64(buffer)); + + parcBuffer_Release(&buffer); + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, parcBufferComposer_PutUint8) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + + uint8_t byte = 0x01; + parcBufferComposer_PutUint8(composer, byte); + + PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer); + assertTrue(parcBuffer_GetUint8(buffer) == byte, "Expected inserted byte to be equal to %x, got %x", byte, parcBuffer_GetUint8(buffer)); + + parcBuffer_Release(&buffer); + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, parcBufferComposer_PutString) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + + char string[14] = "Hello, World!"; + parcBufferComposer_PutString(composer, string); + + PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer); + char *actual = parcBuffer_ToString(buffer); + assertTrue(strncmp(actual, string, strlen(string)) == 0, + "Expected inserted string to be equal to %s, got %s", string, actual); + + parcMemory_Deallocate((void **) &actual); + parcBuffer_Release(&buffer); + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, parcBufferComposer_PutStrings) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + + char string[14] = "Hello, World!"; + parcBufferComposer_PutStrings(composer, "Hello", ", ", "World!", NULL); + + PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer); + char *actual = parcBuffer_ToString(buffer); + assertTrue(strncmp(actual, string, strlen(string)) == 0, "Expected inserted string to be equal to %s, got %s", string, actual); + + parcMemory_Deallocate((void **) &actual); + parcBuffer_Release(&buffer); + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, parcBufferComposer_Format) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + parcBufferComposer_Format(composer, "hello %s", "world"); + + PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer); + + char expected[11] = "hello world"; + char *actual = parcBuffer_ToString(buffer); + assertTrue(strncmp(expected, actual, 11) == 0, "Expected strings to match. Got %s, expected %s", actual, expected); + + parcMemory_Deallocate((void **) &actual); + parcBuffer_Release(&buffer); + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, parcBufferComposer_PutChar) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + + char byte = 'a'; + parcBufferComposer_PutChar(composer, byte); + + PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer); + assertTrue(parcBuffer_GetUint8(buffer) == byte, "Expected inserted char to be equal to %c, got %c", byte, parcBuffer_GetUint8(buffer)); + + parcBuffer_Release(&buffer); + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, parcBufferComposer_CreateBuffer) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + parcBufferComposer_PutString(composer, "hello world"); + + PARCBuffer *buffer = parcBufferComposer_CreateBuffer(composer); + parcBuffer_Flip(buffer); // flip the buffer since it was returned in write mode + + char expected[11] = "hello world"; + char *actual = parcBuffer_ToString(buffer); + assertTrue(strncmp(expected, actual, 11) == 0, "Expected strings to match. Got %s, expected %s", actual, expected); + + parcMemory_Deallocate((void **) &actual); + parcBuffer_Release(&buffer); + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, parcBufferComposer_ProduceBuffer) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + parcBufferComposer_PutString(composer, "hello world"); + + PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer); + + char expected[11] = "hello world"; + char *actual = parcBuffer_ToString(buffer); + assertTrue(strncmp(expected, actual, 11) == 0, "Expected strings to match. Got %s, expected %s", actual, expected); + + parcMemory_Deallocate((void **) &actual); + parcBuffer_Release(&buffer); + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, parcBufferComposer_PutString_Extend) +{ + PARCBufferComposer *composer = parcBufferComposer_Allocate(4); + parcBufferComposer_PutString(composer, "hello world"); + + PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer); + + char expected[11] = "hello world"; + char *actual = parcBuffer_ToString(buffer); + assertTrue(strncmp(expected, actual, 11) == 0, "Expected strings to match. Got %s, expected %s", actual, expected); + + parcMemory_Deallocate((void **) &actual); + parcBuffer_Release(&buffer); + parcBufferComposer_Release(&composer); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_BufferComposer); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_ByteArray.c b/libparc/parc/algol/test/test_parc_ByteArray.c new file mode 100755 index 00000000..971d79dd --- /dev/null +++ b/libparc/parc/algol/test/test_parc_ByteArray.c @@ -0,0 +1,499 @@ +/* + * 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. + */ + +/** + * @file test_parc_ByteArray.c + * + */ +#include "../parc_ByteArray.c" +#include <stdio.h> + +#include <LongBow/unit-test.h> +#include <LongBow/debugging.h> +#include <stdio.h> + +#include <parc/algol/parc_SafeMemory.h> +#include <parc/testing/parc_ObjectTesting.h> + +LONGBOW_TEST_RUNNER(PARCByteArray) +{ + // 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(PARCByteArray) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(PARCByteArray) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Acquire); + LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Acquire_destroyoriginal); + LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Allocate); + LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Allocate_ZeroLength); + + LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Wrap_NULL); + LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Wrap_ZeroLength); + + LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Wrap); + LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Array); + LONGBOW_RUN_TEST_CASE(Global, parcByteArray_AddressOfIndex); + LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Capacity); + LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Copy_Allocated); + LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Copy_Wrapped); + LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Compare); + LONGBOW_RUN_TEST_CASE(Global, parcByteArray_PutBytes); + LONGBOW_RUN_TEST_CASE(Global, parcByteArray_CopyOut); + LONGBOW_RUN_TEST_CASE(Global, parcByteArray_CopyInByteArray); + LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Get); + LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Put); + LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Equals); + LONGBOW_RUN_TEST_CASE(Global, parcByteArray_HashCode); + LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Release); + LONGBOW_RUN_TEST_CASE(Global, parcByteArray_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, parcByteArray_Allocate) +{ + PARCByteArray *actual = parcByteArray_Allocate(10); + + parcByteArray_Release(&actual); +} + +LONGBOW_TEST_CASE(Global, parcByteArray_Allocate_ZeroLength) +{ + PARCByteArray *actual = parcByteArray_Allocate(0); + assertNotNull(actual, "parcByteArray_Allocate(0) must not return NULL."); + assertTrue(parcByteArray_Capacity(actual) == 0, "Expected capacity to be 0"); + + parcByteArray_Release(&actual); +} + +LONGBOW_TEST_CASE(Global, parcByteArray_Wrap) +{ + uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCByteArray *actual = parcByteArray_Wrap(10, buffer); + + parcByteArray_Release(&actual); +} + +LONGBOW_TEST_CASE(Global, parcByteArray_Wrap_NULL) +{ + PARCByteArray *actual = parcByteArray_Wrap(10, NULL); + + assertNull(actual, "Expected NULL return value from parcByteArray_Wrap()"); +} + +LONGBOW_TEST_CASE(Global, parcByteArray_Wrap_ZeroLength) +{ + PARCByteArray *actual = parcByteArray_Wrap(0, (uint8_t[1]) { 0 }); + + assertNotNull(actual, "Expected non-NULL return value from parcByteArray_Wrap()"); + assertTrue(parcByteArray_Capacity(actual) == 0, "Expected capacity to be zero."); + parcByteArray_Release(&actual); +} + +LONGBOW_TEST_CASE(Global, parcByteArray_Array) +{ + uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCByteArray *actual = parcByteArray_Wrap(10, buffer); + assertTrue(buffer == parcByteArray_Array(actual), "Expected the array to be the wrapped array."); + + parcByteArray_Release(&actual); +} + +LONGBOW_TEST_CASE(Global, parcByteArray_AddressOfIndex) +{ + uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCByteArray *actual = parcByteArray_Wrap(10, buffer); + uint8_t *address = parcByteArray_AddressOfIndex(actual, 3); + + assertTrue(buffer[3] == *address, + "Expected %d, actual %d", buffer[3], *address); + + parcByteArray_Release(&actual); +} + + +LONGBOW_TEST_CASE(Global, parcByteArray_Release) +{ + PARCByteArray *actual = parcByteArray_Allocate(10); + + parcByteArray_Release(&actual); + assertNull(actual, "Expected the pointer to be NULL after parcByteArray_Release"); +} + +LONGBOW_TEST_CASE(Global, parcByteArray_Copy_Allocated) +{ + uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCByteArray *original = parcByteArray_Allocate(sizeof(buffer)); + parcByteArray_PutBytes(original, 0, sizeof(buffer), buffer); + + PARCByteArray *clone = parcByteArray_Copy(original); + + assertTrue(original != clone, "Expected clone to be a different instance that original."); + + assertTrue(parcByteArray_Equals(original, clone), "Expected the clone to be equal to the original."); + + parcByteArray_Release(&original); + parcByteArray_Release(&clone); +} + +LONGBOW_TEST_CASE(Global, parcByteArray_Copy_Wrapped) +{ + uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCByteArray *original = parcByteArray_Wrap(sizeof(buffer), buffer); + + PARCByteArray *clone = parcByteArray_Copy(original); + + assertTrue(original != clone, "Expected clone to be a different instance that original."); + + assertTrue(parcByteArray_Equals(original, clone), "Expected the clone to be equal to the original."); + + parcByteArray_Release(&original); + parcByteArray_Release(&clone); +} + +LONGBOW_TEST_CASE(Global, parcByteArray_Compare) +{ + uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCByteArray *x = parcByteArray_Wrap(sizeof(buffer), buffer); + + PARCByteArray **equivalents = (PARCByteArray *[]) { + parcByteArray_Wrap(sizeof(buffer), buffer), + NULL + }; + PARCByteArray **lessers = (PARCByteArray *[]) { + parcByteArray_Wrap(sizeof(buffer) - 1, buffer), + parcByteArray_Wrap(sizeof(buffer) - 1, (uint8_t[]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8 }), + NULL + }; + PARCByteArray **greaters = (PARCByteArray *[]) { + parcByteArray_Wrap(11, (uint8_t[]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }), + parcByteArray_Wrap(10, (uint8_t[]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10 }), + NULL + }; + /* + * (a - b) + */ + parcObjectTesting_AssertCompareTo(parcByteArray_Compare, x, equivalents, lessers, greaters); + + parcByteArray_Release(&x); + + for (int i = 0; equivalents[i] != NULL; i++) { + parcByteArray_Release(&equivalents[i]); + } + for (int i = 0; lessers[i] != NULL; i++) { + parcByteArray_Release(&lessers[i]); + } + for (int i = 0; greaters[i] != NULL; i++) { + parcByteArray_Release(&greaters[i]); + } +} + +LONGBOW_TEST_CASE(Global, parcByteArray_Equals) +{ + uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCByteArray *x = parcByteArray_Wrap(10, buffer); + PARCByteArray *y = parcByteArray_Wrap(10, buffer); + PARCByteArray *z = parcByteArray_Wrap(10, buffer); + PARCByteArray *u1 = parcByteArray_Wrap(5, buffer); + PARCByteArray *u2 = parcByteArray_Allocate(5); + + parcObjectTesting_AssertEqualsFunction(parcByteArray_Equals, x, y, z, u1, u2, NULL); + + parcByteArray_Release(&x); + parcByteArray_Release(&y); + parcByteArray_Release(&z); + parcByteArray_Release(&u1); + parcByteArray_Release(&u2); +} + +LONGBOW_TEST_CASE(Global, parcByteArray_Capacity) +{ + size_t expected = 10; + + PARCByteArray *actual = parcByteArray_Allocate(expected); + assertTrue(expected == parcByteArray_Capacity(actual), "Expected %zd, actual %zd", expected, parcByteArray_Capacity(actual)); + + parcByteArray_Release(&actual); +} + +LONGBOW_TEST_CASE(Global, parcByteArray_CopyOut) +{ + uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + uint8_t actual[10]; + + PARCByteArray *original = parcByteArray_Wrap(10, expected); + parcByteArray_GetBytes(original, 0, sizeof(actual), actual); + + assertTrue(memcmp(expected, actual, sizeof(actual)) == 0, + "Expected parcByteArray_CopyOut to copy the orginal data"); + + parcByteArray_Release(&original); +} + +LONGBOW_TEST_CASE(Global, parcByteArray_PutBytes) +{ + uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + uint8_t actual[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + PARCByteArray *original = parcByteArray_Wrap(10, expected); + parcByteArray_PutBytes(original, 0, 10, actual); + + assertTrue(memcmp(expected, actual, 10) == 0, + "Expected parcByteArray_CopyOut to copy the orginal data"); + + parcByteArray_Release(&original); +} + +LONGBOW_TEST_CASE(Global, parcByteArray_CopyInByteArray) +{ + uint8_t array1[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + uint8_t array2[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + uint8_t expected[10] = { 0, 1, 2, 0, 0, 0, 6, 7, 8, 9 }; + + PARCByteArray *a1 = parcByteArray_Wrap(10, array1); + PARCByteArray *a2 = parcByteArray_Wrap(10, array2); + parcByteArray_ArrayCopy(a1, 3, a2, 0, 3); + + assertTrue(memcmp(expected, parcByteArray_Array(a1), 10) == 0, + "Expected parcByteArray_CopyOut to copy the orginal data"); + + parcByteArray_Release(&a1); + parcByteArray_Release(&a2); +} + +LONGBOW_TEST_CASE(Global, parcByteArray_Get) +{ + uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCByteArray *original = parcByteArray_Wrap(10, buffer); + + for (uint8_t index = 0; index < 10; index++) { + uint8_t actual = parcByteArray_GetByte(original, index); + assertTrue(index == actual, "Expected %d, actual %d", index, actual); + } + parcByteArray_Release(&original); +} + +LONGBOW_TEST_CASE(Global, parcByteArray_Put) +{ + uint8_t buffer[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + PARCByteArray *original = parcByteArray_Wrap(10, buffer); + + for (uint8_t index = 0; index < 10; index++) { + parcByteArray_PutByte(original, index, index); + } + + for (uint8_t index = 0; index < 10; index++) { + uint8_t actual = parcByteArray_GetByte(original, index); + assertTrue(index == actual, "Expected %d, actual %d", index, actual); + } + + parcByteArray_Release(&original); +} + +LONGBOW_TEST_CASE(Global, parcByteArray_Acquire) +{ + uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCByteArray *actual = parcByteArray_Wrap(10, buffer); + PARCByteArray *reference = parcByteArray_Acquire(actual); + + assertTrue(reference == actual, "Expected the new reference to be equal to the original."); + + PARCByteArray *new1 = parcByteArray_Acquire(actual); + assertTrue(new1 == actual, "Expected new to be the same as actual"); + + PARCByteArray *new2 = parcByteArray_Acquire(actual); + assertTrue(new2 == actual, "Expected new to be the same as actual"); + + parcByteArray_Release(&new1); + assertNull(new1, "Expected destroy to null the pointer"); + assertNotNull(actual, "Expected destroy to NOT null the original pointer"); + + parcByteArray_Release(&new2); + assertNull(new1, "Expected destroy to null the pointer"); + assertNotNull(actual, "Expected destroy to NOT null the original pointer"); + + parcByteArray_Release(&reference); + parcByteArray_Release(&actual); +} + +LONGBOW_TEST_CASE(Global, parcByteArray_Acquire_destroyoriginal) +{ + uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCByteArray *original = parcByteArray_Wrap(10, buffer); + + PARCByteArray *ref1 = parcByteArray_Acquire(original); + assertTrue(ref1 == original, "Expected new to be the same as original"); + + parcByteArray_Release(&original); + assertNull(original, "Expected destroy to null the pointer"); + assertNotNull(ref1, "Expected destroy to NOT null the new reference"); + + parcByteArray_Release(&ref1); +} + +LONGBOW_TEST_CASE(Global, parcByteArray_HashCode) +{ + uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCByteArray *x = parcByteArray_Wrap(10, buffer); + PARCByteArray *y = parcByteArray_Wrap(10, buffer); + + PARCHashCode hashX = parcByteArray_HashCode(x); + PARCHashCode hashY = parcByteArray_HashCode(y); + + assertTrue(hashX == hashY, + "Expected %" PRIPARCHashCode ", actual %" PRIPARCHashCode, hashX, hashY); + + parcByteArray_Release(&x); + parcByteArray_Release(&y); +} + +LONGBOW_TEST_CASE(Global, parcByteArray_Display) +{ + uint8_t buffer[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 }; + + PARCByteArray *x = parcByteArray_Wrap(sizeof(buffer), buffer); + + parcByteArray_Display(x, 0); + + parcByteArray_Release(&x); +} + +LONGBOW_TEST_FIXTURE(Errors) +{ + LONGBOW_RUN_TEST_CASE(Errors, parcByteArray_Put_overrun); + LONGBOW_RUN_TEST_CASE(Errors, parcByteArray_Get_overrun); + LONGBOW_RUN_TEST_CASE(Errors, parcByteArray_CopyIn_overrun); + LONGBOW_RUN_TEST_CASE(Errors, parcByteArray_CopyOut_overrun); +} + +typedef struct parc_byte_array_longbow_clipboard { + PARCByteArray *byteArray; +} parcByteArray_LongBowClipBoard; + +LONGBOW_TEST_FIXTURE_SETUP(Errors) +{ + parcByteArray_LongBowClipBoard *clipboardData = calloc(1, sizeof(parcByteArray_LongBowClipBoard)); + clipboardData->byteArray = parcByteArray_Allocate(10); + + longBowTestCase_SetClipBoardData(testCase, clipboardData); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Errors) +{ + parcByteArray_LongBowClipBoard *clipboardData = longBowTestCase_GetClipBoardData(testCase); + parcByteArray_Release(&clipboardData->byteArray); + free(clipboardData); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE_EXPECTS(Errors, parcByteArray_Put_overrun, .event = &LongBowTrapOutOfBounds) +{ + parcByteArray_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase); + PARCByteArray *original = testData->byteArray; + + for (uint8_t index = 0; index < 10 + 1; index++) { + parcByteArray_PutByte(original, index, index); // This will fail. + } +} + +LONGBOW_TEST_CASE_EXPECTS(Errors, parcByteArray_CopyIn_overrun, .event = &LongBowTrapOutOfBounds) +{ + uint8_t actual[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + parcByteArray_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase); + PARCByteArray *original = testData->byteArray; + parcByteArray_GetBytes(original, 1, 10, actual); // This will fail. +} + +LONGBOW_TEST_CASE_EXPECTS(Errors, parcByteArray_CopyOut_overrun, .event = &LongBowTrapOutOfBounds) +{ + uint8_t actual[10]; + + parcByteArray_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase); + PARCByteArray *original = testData->byteArray; + parcByteArray_GetBytes(original, 1, 10, actual); // This will fail. +} + +LONGBOW_TEST_CASE_EXPECTS(Errors, parcByteArray_Get_overrun, .event = &LongBowTrapOutOfBounds) +{ + uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + parcByteArray_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase); + PARCByteArray *original = testData->byteArray; + parcByteArray_PutBytes(original, 0, 10, buffer); + + for (uint8_t index = 0; index < 10 + 1; index++) { + uint8_t actual = parcByteArray_GetByte(original, index); // this will fail. + assertTrue(index == actual, "Expected %d, actual %d", index, actual); + } +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(PARCByteArray); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_Chunker.c b/libparc/parc/algol/test/test_parc_Chunker.c new file mode 100755 index 00000000..945e6bab --- /dev/null +++ b/libparc/parc/algol/test/test_parc_Chunker.c @@ -0,0 +1,271 @@ +/* + * 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 "../parc_Chunker.c" + +#include <stdio.h> + +#include <parc/algol/parc_Object.h> + +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + +typedef struct { + int val; + int dir; + bool atEnd; +} _DummyChunkerState; + +typedef struct { + int start; + int end; + bool released; + size_t chunkSize; +} _DummyChunker; + +static void * +_InitForward(_DummyChunker *chunker) +{ + _DummyChunkerState *state = parcMemory_Allocate(sizeof(_DummyChunkerState)); + + state->val = 0; + state->dir = 1; + state->atEnd = false; + + return state; +} + +static bool +_hasNext(_DummyChunker *chunker, void *voidstate) +{ + _DummyChunkerState *state = (_DummyChunkerState *) voidstate; + return !state->atEnd; +} + +static void * +_next(_DummyChunker *chunker, void *voidstate) +{ + _DummyChunkerState *state = (_DummyChunkerState *) voidstate; + state->val++; + + if (state->val == chunker->end) { + state->atEnd = true; + } + + return state; +} + +static void * +_get(_DummyChunker *chunker, void *voidstate) +{ + _DummyChunkerState *state = (_DummyChunkerState *) voidstate; + return &(state->val); +} + +static void +_finish(_DummyChunker *chunker, void *state) +{ + _DummyChunkerState *thestate = (_DummyChunkerState *) state; + parcMemory_Deallocate(&thestate); +} + +static PARCIterator * +_mock_ForwardIterator(const void *chunker) +{ + PARCIterator *iterator = parcIterator_Create((void *) chunker, + (void *(*)(PARCObject *))_InitForward, + (bool (*)(PARCObject *, void *))_hasNext, + (void *(*)(PARCObject *, void *))_next, + NULL, + (void *(*)(PARCObject *, void *))_get, + (void (*)(void *, void *))_finish, + NULL); + + return iterator; +} + +static PARCIterator * +_mock_ReverseIterator(const void *chunker) +{ + PARCIterator *iterator = parcIterator_Create((void *) chunker, + (void *(*)(PARCObject *))_InitForward, + (bool (*)(PARCObject *, void *))_hasNext, + (void *(*)(PARCObject *, void *))_next, + NULL, + (void *(*)(PARCObject *, void *))_get, + (void (*)(void *, void *))_finish, + NULL); + + return iterator; +} + +static size_t +_mock_GetChunkSize(const void *chunker) +{ + _DummyChunker *dummy = (_DummyChunker *) chunker; + return dummy->chunkSize; +} + +static void +_dummyDestroy(_DummyChunker **chunkerP) +{ + // pass... +} + +PARCChunkerInterface *_MockChunker = &(PARCChunkerInterface) { + .ForwardIterator = (void *(*)(const void *))_mock_ForwardIterator, + .ReverseIterator = (void *(*)(const void *))_mock_ReverseIterator, + .GetChunkSize = (size_t (*)(const void *))_mock_GetChunkSize +}; + +parcObject_ExtendPARCObject(_DummyChunker, _dummyDestroy, NULL, NULL, NULL, NULL, NULL, NULL); +parcObject_ImplementAcquire(_dummy, _DummyChunker); +parcObject_ImplementRelease(_dummy, _DummyChunker); + +static _DummyChunker * +_dummy_Create(int val) +{ + _DummyChunker *chunker = (_DummyChunker *) parcObject_CreateAndClearInstance(_DummyChunker); + chunker->start = 0; + chunker->end = val; + chunker->released = false; + chunker->chunkSize = val; + return chunker; +} + +LONGBOW_TEST_RUNNER(parc_Chunker) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_Chunker) +{ + 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(parc_Chunker) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_Create); + LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ForwardIterator); + LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ReverseIterator); + LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_GetChunkSize); +} + +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, parc_Chunker_Create) +{ + _DummyChunker *dummy = _dummy_Create(10); + PARCChunker *chunker = parcChunker_Create(dummy, _MockChunker); + _dummy_Release(&dummy); + + assertNotNull(chunker, "Expected non-NULL PARCChunker to be created from the dummy MockChunker"); + PARCChunker *copy = parcChunker_Acquire(chunker); + assertNotNull(copy, "Expected non-NULL copy of the PARCChunker"); + + parcChunker_Release(&chunker); + parcChunker_Release(©); +} + +LONGBOW_TEST_CASE(Global, parc_Chunker_ForwardIterator) +{ + int n = 10; + + _DummyChunker *dummy = _dummy_Create(n); + PARCChunker *chunker = parcChunker_Create(dummy, _MockChunker); + _dummy_Release(&dummy); + PARCIterator *itr = parcChunker_ForwardIterator(chunker); + + int targetSum = (n * (n + 1)) / 2; + int sum = 0; + while (parcIterator_HasNext(itr)) { + int *val = parcIterator_Next(itr); + sum += *val; + } + assertTrue(targetSum == sum, "Expected the iterator to walk the chunker as needed\n"); + + parcIterator_Release(&itr); + parcChunker_Release(&chunker); +} + +LONGBOW_TEST_CASE(Global, parc_Chunker_ReverseIterator) +{ + int n = 10; + + _DummyChunker *dummy = _dummy_Create(n); + PARCChunker *chunker = parcChunker_Create(dummy, _MockChunker); + _dummy_Release(&dummy); + PARCIterator *itr = parcChunker_ReverseIterator(chunker); + + int targetSum = (n * (n + 1)) / 2; + int sum = 0; + while (parcIterator_HasNext(itr)) { + int *val = parcIterator_Next(itr); + sum += *val; + } + assertTrue(targetSum == sum, "Expected the iterator to walk the chunker as needed\n"); + + parcIterator_Release(&itr); + parcChunker_Release(&chunker); +} + +LONGBOW_TEST_CASE(Global, parc_Chunker_GetChunkSize) +{ + int n = 10; + + _DummyChunker *dummy = _dummy_Create(n); + PARCChunker *chunker = parcChunker_Create(dummy, _MockChunker); + _dummy_Release(&dummy); + + size_t chunkSize = parcChunker_GetChunkSize(chunker); + assertTrue(chunkSize == n, "Expected the chunk size to be %d, got %zu\n", n, chunkSize); + + parcChunker_Release(&chunker); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Chunker); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_Clock.c b/libparc/parc/algol/test/test_parc_Clock.c new file mode 100644 index 00000000..0adf813e --- /dev/null +++ b/libparc/parc/algol/test/test_parc_Clock.c @@ -0,0 +1,198 @@ +/* + * 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 "../parc_Clock.c" +#include <stdio.h> +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + +LONGBOW_TEST_RUNNER(parc_Clock) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_Clock) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_Clock) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ========================================================== + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcClock_Wallclock); + LONGBOW_RUN_TEST_CASE(Global, parcClock_Wallclock_Acquire); + LONGBOW_RUN_TEST_CASE(Global, parcClock_Wallclock_GetTime); + LONGBOW_RUN_TEST_CASE(Global, parcClock_Wallclock_GetTimeval); + LONGBOW_RUN_TEST_CASE(Global, parcClock_Montonic); + LONGBOW_RUN_TEST_CASE(Global, parcClock_Monotonic_Acquire); + LONGBOW_RUN_TEST_CASE(Global, parcClock_Monotonic_GetTime); + LONGBOW_RUN_TEST_CASE(Global, parcClock_Monotonic_GetTimeval); + + LONGBOW_RUN_TEST_CASE(Global, counterClock_Create); + LONGBOW_RUN_TEST_CASE(Global, counterClock_Acquire); + LONGBOW_RUN_TEST_CASE(Global, counterClock_GetTime); + LONGBOW_RUN_TEST_CASE(Global, counterClock_GetTime_Twice); + LONGBOW_RUN_TEST_CASE(Global, counterClock_GetTimeval); +} + +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, parcClock_Wallclock) +{ + PARCClock *clock = parcClock_Wallclock(); + assertNotNull(clock, "Got null wall clock"); + parcClock_Release(&clock); +} + +LONGBOW_TEST_CASE(Global, parcClock_Wallclock_Acquire) +{ + PARCClock *clock = parcClock_Wallclock(); + PARCClock *copy = parcClock_Acquire(clock); + assertNotNull(copy, "Got null wall clock"); + parcClock_Release(©); + parcClock_Release(&clock); +} + +LONGBOW_TEST_CASE(Global, parcClock_Wallclock_GetTime) +{ + PARCClock *clock = parcClock_Wallclock(); + uint64_t t = parcClock_GetTime(clock); + parcClock_Release(&clock); + assertTrue(t > 0, "got 0 time"); +} + +LONGBOW_TEST_CASE(Global, parcClock_Wallclock_GetTimeval) +{ + PARCClock *clock = parcClock_Wallclock(); + struct timeval tv = { 0, 0 }; + parcClock_GetTimeval(clock, &tv); + parcClock_Release(&clock); + assertTrue(tv.tv_sec > 0, "Got 0 seconds"); +} + +// ----- + +LONGBOW_TEST_CASE(Global, parcClock_Montonic) +{ + PARCClock *clock = parcClock_Monotonic(); + assertNotNull(clock, "Got null wall clock"); + parcClock_Release(&clock); +} + +LONGBOW_TEST_CASE(Global, parcClock_Monotonic_Acquire) +{ + PARCClock *clock = parcClock_Monotonic(); + PARCClock *copy = parcClock_Acquire(clock); + assertNotNull(copy, "Got null wall clock"); +} + +LONGBOW_TEST_CASE(Global, parcClock_Monotonic_GetTime) +{ + PARCClock *clock = parcClock_Monotonic(); + uint64_t t = parcClock_GetTime(clock); + parcClock_Release(&clock); + assertTrue(t > 0, "got 0 time"); +} + +LONGBOW_TEST_CASE(Global, parcClock_Monotonic_GetTimeval) +{ + PARCClock *clock = parcClock_Monotonic(); + struct timeval tv = { 0, 0 }; + parcClock_GetTimeval(clock, &tv); + parcClock_Release(&clock); + assertTrue(tv.tv_sec > 0, "Got 0 seconds"); +} + +// ----- + +LONGBOW_TEST_CASE(Global, counterClock_Create) +{ + PARCClock *clock = parcClock_Counter(); + assertNotNull(clock, "Got null wall clock"); + parcClock_Release(&clock); +} + +LONGBOW_TEST_CASE(Global, counterClock_Acquire) +{ + PARCClock *clock = parcClock_Counter(); + PARCClock *copy = parcClock_Acquire(clock); + assertNotNull(copy, "Got null wall clock"); + parcClock_Release(©); + parcClock_Release(&clock); +} + +LONGBOW_TEST_CASE(Global, counterClock_GetTime) +{ + PARCClock *clock = parcClock_Counter(); + uint64_t t = parcClock_GetTime(clock); + parcClock_Release(&clock); + assertTrue(t == 1, "On first call should have gotten 1"); +} + +LONGBOW_TEST_CASE(Global, counterClock_GetTime_Twice) +{ + PARCClock *clock = parcClock_Counter(); + parcClock_GetTime(clock); + uint64_t t2 = parcClock_GetTime(clock); + parcClock_Release(&clock); + assertTrue(t2 == 2, "On second call should have gotten 2"); +} + +LONGBOW_TEST_CASE(Global, counterClock_GetTimeval) +{ + PARCClock *clock = parcClock_Counter(); + struct timeval tv = { 0, 0 }; + parcClock_GetTimeval(clock, &tv); + parcClock_Release(&clock); + assertTrue(tv.tv_usec == 1, "On first call should have gotten 1 usec"); +} + + +// ========================================================== + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Clock); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} + diff --git a/libparc/parc/algol/test/test_parc_Deque.c b/libparc/parc/algol/test/test_parc_Deque.c new file mode 100755 index 00000000..02884b4a --- /dev/null +++ b/libparc/parc/algol/test/test_parc_Deque.c @@ -0,0 +1,620 @@ +/* + * 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 "../parc_Deque.c" +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> +#include <parc/algol/parc_StdlibMemory.h> + +#include <parc/testing/parc_ObjectTesting.h> +#include <parc/testing/parc_MemoryTesting.h> + +LONGBOW_TEST_RUNNER(parc_Deque) +{ + // 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(Local); + LONGBOW_RUN_TEST_FIXTURE(AcquireRelease); + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Performance); +// LONGBOW_RUN_TEST_FIXTURE(Errors); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_Deque) +{ + 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(parc_Deque) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(AcquireRelease) +{ + LONGBOW_RUN_TEST_CASE(AcquireRelease, parcDeque_CreateRelease); + LONGBOW_RUN_TEST_CASE(AcquireRelease, parcDeque_CreateRelease_WithEquals); + LONGBOW_RUN_TEST_CASE(AcquireRelease, parcDeque_AcquireRelease); +} + +LONGBOW_TEST_FIXTURE_SETUP(AcquireRelease) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(AcquireRelease) +{ + bool leaked = parcMemoryTesting_ExpectedOutstanding(0, "%s leaks memory \n", longBowTestCase_GetName(testCase)) != true; + if (leaked) { + parcSafeMemory_ReportAllocation(STDOUT_FILENO); + printf("bailing\n"); + exit(1); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(AcquireRelease, parcDeque_CreateRelease) +{ + PARCDeque *deque = parcDeque_Create(); + assertNotNull(deque, "Expected non-null result from parcDeque_Create()"); + + parcDeque_Release(&deque); + assertNull(deque, "Expected parcDeque_Release to null the pointer"); +} + +LONGBOW_TEST_CASE(AcquireRelease, parcDeque_CreateRelease_WithEquals) +{ + PARCDeque *deque = parcDeque_CreateCustom(NULL, NULL); + assertNotNull(deque, "Expected non-null result from parcDeque_Create()"); + + parcDeque_Release(&deque); + assertNull(deque, "Expected parcDeque_Release to null the pointer"); +} + +LONGBOW_TEST_CASE(AcquireRelease, parcDeque_AcquireRelease) +{ + PARCDeque *original = parcDeque_Create(); + assertNotNull(original, "Expected non-null result from parcDeque_Create()"); + + parcObjectTesting_AssertAcquireReleaseContract(parcDeque_Acquire, original); + + PARCDeque *reference = parcDeque_Acquire(original); + assertTrue(original == reference, "Expected the reference to be equal to the original."); + + parcDeque_Release(&original); + assertNull(original, "Expected parcDeque_Release to null the pointer"); + + parcDeque_Append(reference, (void *) 1); + size_t expected = 1; + size_t actual = parcDeque_Size(reference); + assertTrue(expected == actual, + "Expected size %zd, actual %zd", expected, actual); + parcDeque_Release(&reference); +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcDeque_Append_One); + LONGBOW_RUN_TEST_CASE(Global, parcDeque_Append_Two); + LONGBOW_RUN_TEST_CASE(Global, parcDeque_CreateDestroy); + LONGBOW_RUN_TEST_CASE(Global, parcDeque_PeekFirst); + LONGBOW_RUN_TEST_CASE(Global, parcDeque_PeekLast); + + LONGBOW_RUN_TEST_CASE(Global, parcDeque_Prepend_One); + LONGBOW_RUN_TEST_CASE(Global, parcDeque_Prepend_Two); + LONGBOW_RUN_TEST_CASE(Global, parcDeque_Prepend_Three); + + LONGBOW_RUN_TEST_CASE(Global, parcDeque_IsEmpty); + LONGBOW_RUN_TEST_CASE(Global, parcDeque_GetAtIndex); + + LONGBOW_RUN_TEST_CASE(Global, parcDeque_RemoveFirst); + LONGBOW_RUN_TEST_CASE(Global, parcDeque_RemoveFirst_SingleElement); + LONGBOW_RUN_TEST_CASE(Global, parcDeque_RemoveLast); + LONGBOW_RUN_TEST_CASE(Global, parcDeque_Size); + LONGBOW_RUN_TEST_CASE(Global, parcDeque_Equals); + LONGBOW_RUN_TEST_CASE(Global, parcDeque_Copy); + LONGBOW_RUN_TEST_CASE(Global, parcDeque_Display); + LONGBOW_RUN_TEST_CASE(Global, parcDeque_Display_NULL); + + LONGBOW_RUN_TEST_CASE(Global, parcDeque_Iterator); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + bool leaked = parcMemoryTesting_ExpectedOutstanding(0, "%s leaks memory \n", longBowTestCase_GetName(testCase)) != true; + if (leaked) { + parcSafeMemory_ReportAllocation(STDOUT_FILENO); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, parcDeque_Append_One) +{ + PARCDeque *deque = parcDeque_Create(); + PARCDeque *actual = parcDeque_Append(deque, "element 1"); + + assertTrue(deque == actual, "Expected parcDeque_Append to return its argument."); + assertTrue(parcDeque_Size(deque) == 1, "Expected size of 1, actual %zd", parcDeque_Size(deque)); + + parcDeque_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcDeque_Append_Two) +{ + PARCDeque *deque = parcDeque_Create(); + parcDeque_Append(deque, "element 1"); + PARCDeque *actual = parcDeque_Append(deque, "element 2"); + + assertTrue(deque == actual, "Expected parcDeque_Append to return its argument."); + assertTrue(parcDeque_Size(deque) == 2, "Expected size of 2, actual %zd", parcDeque_Size(deque)); + + parcDeque_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcDeque_CreateDestroy) +{ + PARCDeque *deque = parcDeque_Create(); + assertNotNull(deque, "Expected non-null result from parcDeque_Create()"); + + parcDeque_Release(&deque); + assertNull(deque, "Expected parcDeque_Destroy to null the pointer"); +} + +LONGBOW_TEST_CASE(Global, parcDeque_PeekFirst) +{ + char *expected = "element 2"; + PARCDeque *deque = parcDeque_Create(); + parcDeque_Append(deque, expected); + parcDeque_Append(deque, "element 2"); + parcDeque_Append(deque, "element 3"); + + char *actual = parcDeque_PeekFirst(deque); + assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual); + + parcDeque_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcDeque_PeekLast) +{ + char *expected = "element 2"; + PARCDeque *deque = parcDeque_Create(); + parcDeque_Append(deque, "element 1"); + parcDeque_Append(deque, "element 2"); + parcDeque_Append(deque, expected); + + char *actual = parcDeque_PeekLast(deque); + assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual); + + parcDeque_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcDeque_Prepend_One) +{ + PARCDeque *deque = parcDeque_Create(); + PARCDeque *actual = parcDeque_Prepend(deque, "element 1"); + + assertTrue(deque == actual, "Expected parcDeque_Append to return its argument."); + assertTrue(parcDeque_Size(deque) == 1, "Expected size of 1, actual %zd", parcDeque_Size(deque)); + assertTrue(deque->head != NULL, "Expected head to be not null."); + assertTrue(deque->head == deque->tail, "Expected head to be equal to the tail."); + + parcDeque_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcDeque_Prepend_Two) +{ + PARCDeque *deque = parcDeque_Create(); + parcDeque_Prepend(deque, "element 2"); + PARCDeque *actual = parcDeque_Prepend(deque, "element 1"); + + assertTrue(deque == actual, "Expected parcDeque_Prepend to return its argument."); + assertTrue(parcDeque_Size(deque) == 2, "Expected size of 2, actual %zd", parcDeque_Size(deque)); + + parcDeque_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcDeque_Prepend_Three) +{ + char *expectedFirst = "expected first"; + char *expectedLast = "expected last"; + + PARCDeque *deque = parcDeque_Create(); + parcDeque_Prepend(deque, expectedLast); + parcDeque_Prepend(deque, "element 2"); + PARCDeque *actual = parcDeque_Prepend(deque, expectedFirst); + + assertTrue(deque == actual, "Expected parcDeque_Prepend to return its argument."); + assertTrue(parcDeque_Size(deque) == 3, "Expected size of 3, actual %zd", parcDeque_Size(deque)); + + char *peek = parcDeque_PeekFirst(deque); + assertTrue(strcmp(expectedFirst, peek) == 0, "Expected '%s' actual '%s'", expectedFirst, peek); + + peek = parcDeque_PeekLast(deque); + assertTrue(strcmp(expectedLast, peek) == 0, "Expected '%s' actual '%s'", expectedLast, peek); + + parcDeque_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcDeque_RemoveFirst) +{ + char *expectedFirst = "expected 1st"; + char *expectedLast = "expected last"; + + PARCDeque *deque = parcDeque_Create(); + parcDeque_Prepend(deque, expectedLast); + parcDeque_Prepend(deque, "element 2"); + parcDeque_Prepend(deque, expectedFirst); + + char *peek = parcDeque_RemoveFirst(deque); + assertTrue(strcmp(expectedFirst, peek) == 0, "Expected '%s' actual '%s'", expectedFirst, peek); + + parcDeque_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcDeque_RemoveFirst_SingleElement) +{ + char *expectedFirst = "expected 1st"; + + PARCDeque *deque = parcDeque_Create(); + parcDeque_Prepend(deque, expectedFirst); + + char *peek = parcDeque_RemoveFirst(deque); + assertTrue(strcmp(expectedFirst, peek) == 0, + "Expected '%s' actual '%s'", expectedFirst, peek); + + parcDeque_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcDeque_RemoveLast) +{ + char *expectedFirst = "expected 1st"; + char *expectedLast = "expected last"; + + PARCDeque *deque = parcDeque_Create(); + parcDeque_Prepend(deque, expectedLast); + parcDeque_Prepend(deque, "element 2"); + parcDeque_Prepend(deque, expectedFirst); + + char *peek = parcDeque_RemoveLast(deque); + assertTrue(strcmp(expectedLast, peek) == 0, + "Expected '%s' actual '%s'", expectedLast, peek); + + parcDeque_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcDeque_RemoveLast_SingleElement) +{ + char *expectedFirst = "expected 1st"; + + PARCDeque *deque = parcDeque_Create(); + parcDeque_Prepend(deque, expectedFirst); + + char *peek = parcDeque_RemoveLast(deque); + assertTrue(strcmp(expectedFirst, peek) == 0, + "Expected '%s' actual '%s'", expectedFirst, peek); + + parcDeque_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcDeque_Size) +{ + char *expectedFirst = "expected 1st"; + char *expectedLast = "expected last"; + + PARCDeque *deque = parcDeque_Create(); + parcDeque_Prepend(deque, expectedLast); + parcDeque_Prepend(deque, "element 2"); + parcDeque_Prepend(deque, expectedFirst); + + assertTrue(parcDeque_Size(deque) == 3, + "Expected 3, actual %zd", parcDeque_Size(deque)); + parcDeque_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcDeque_IsEmpty) +{ + char *expectedLast = "expected last"; + + PARCDeque *deque = parcDeque_Create(); + + assertTrue(parcDeque_IsEmpty(deque), "Expected true."); + parcDeque_Prepend(deque, expectedLast); + assertFalse(parcDeque_IsEmpty(deque), "Expected false."); + parcDeque_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcDeque_GetAtIndex) +{ + char *expected0 = "expected 1"; + char *expected1 = "expected 2"; + char *expected2 = "expected 3"; + + PARCDeque *deque = parcDeque_Create(); + parcDeque_Append(deque, expected0); + parcDeque_Append(deque, expected1); + parcDeque_Append(deque, expected2); + + char *actual; + actual = parcDeque_GetAtIndex(deque, 0); + assertTrue(strcmp(actual, expected0) == 0, "Expected '%s', actual '%s", expected0, actual); + actual = parcDeque_GetAtIndex(deque, 1); + assertTrue(strcmp(actual, expected1) == 0, "Expected '%s', actual '%s", expected1, actual); + actual = parcDeque_GetAtIndex(deque, 2); + assertTrue(strcmp(actual, expected2) == 0, "Expected '%s', actual '%s", expected2, actual); + + parcDeque_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcDeque_Equals) +{ + PARCDeque *x = parcDeque_Create(); + parcDeque_Append(x, (void *) 0); + parcDeque_Append(x, (void *) 1); + parcDeque_Append(x, (void *) 2); + parcDeque_Append(x, (void *) 3); + parcDeque_Append(x, (void *) 4); + parcDeque_Append(x, (void *) 5); + PARCDeque *y = parcDeque_Create(); + parcDeque_Append(y, (void *) 0); + parcDeque_Append(y, (void *) 1); + parcDeque_Append(y, (void *) 2); + parcDeque_Append(y, (void *) 3); + parcDeque_Append(y, (void *) 4); + parcDeque_Append(y, (void *) 5); + PARCDeque *z = parcDeque_Create(); + parcDeque_Append(z, (void *) 0); + parcDeque_Append(z, (void *) 1); + parcDeque_Append(z, (void *) 2); + parcDeque_Append(z, (void *) 3); + parcDeque_Append(z, (void *) 4); + parcDeque_Append(z, (void *) 5); + PARCDeque *u1 = parcDeque_Create(); + parcDeque_Append(u1, (void *) 0); + parcDeque_Append(u1, (void *) 1); + parcDeque_Append(u1, (void *) 2); + parcDeque_Append(u1, (void *) 3); + parcDeque_Append(u1, (void *) 4); + PARCDeque *u2 = parcDeque_Create(); + parcDeque_Append(u2, (void *) 0); + parcDeque_Append(u2, (void *) 1); + parcDeque_Append(u2, (void *) 2); + parcDeque_Append(u2, (void *) 3); + parcDeque_Append(u2, (void *) 4); + parcDeque_Append(u2, (void *) 4); + + parcObjectTesting_AssertEqualsFunction(parcDeque_Equals, x, y, z, u1, u2, NULL); + + parcDeque_Release(&x); + parcDeque_Release(&y); + parcDeque_Release(&z); + parcDeque_Release(&u1); + parcDeque_Release(&u2); +} + +LONGBOW_TEST_CASE(Global, parcDeque_Copy) +{ + PARCDeque *x = parcDeque_Create(); + parcDeque_Append(x, (void *) 0); + parcDeque_Append(x, (void *) 1); + parcDeque_Append(x, (void *) 2); + parcDeque_Append(x, (void *) 3); + parcDeque_Append(x, (void *) 4); + parcDeque_Append(x, (void *) 5); + + PARCDeque *y = parcDeque_Copy(x); + + assertTrue(parcDeque_Equals(x, y), "Expected the copy to be equal to the original."); + + parcDeque_Release(&y); + parcDeque_Release(&x); +} + +LONGBOW_TEST_CASE(Global, parcDeque_Display) +{ + PARCDeque *x = parcDeque_Create(); + parcDeque_Append(x, (void *) 0); + parcDeque_Append(x, (void *) 1); + parcDeque_Append(x, (void *) 2); + parcDeque_Append(x, (void *) 3); + parcDeque_Append(x, (void *) 4); + parcDeque_Append(x, (void *) 5); + + parcDeque_Display(x, 0); + + parcDeque_Release(&x); +} + +LONGBOW_TEST_CASE(Global, parcDeque_Display_NULL) +{ + parcDeque_Display(NULL, 0); +} + +LONGBOW_TEST_CASE(Global, parcDeque_Iterator) +{ + PARCDeque *x = parcDeque_Create(); + for (size_t i = 0; i < 100; i++) { + parcDeque_Append(x, (void *) i); + } + + PARCIterator *iterator = parcDeque_Iterator(x); + size_t expected = 0; + while (parcIterator_HasNext(iterator)) { + size_t actual = (size_t) parcIterator_Next(iterator); + assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual); + expected++; + } + parcIterator_Release(&iterator); + + parcDeque_Release(&x); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, _parcDequeNode_Create); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + bool leaked = parcMemoryTesting_ExpectedOutstanding(0, "%s leaks memory \n", longBowTestCase_GetName(testCase)) != true; + if (leaked) { + parcSafeMemory_ReportAllocation(STDOUT_FILENO); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, _parcDequeNode_Create) +{ + void *element = "element"; + struct parc_deque_node *previous = NULL; + struct parc_deque_node *next = NULL; + + struct parc_deque_node *actual = _parcDequeNode_Create(element, previous, next); + _parcDequeNode_Destroy(NULL, &actual); +} + +LONGBOW_TEST_FIXTURE(Errors) +{ + LONGBOW_RUN_TEST_CASE(Errors, parcDeque_GetAtIndex_OutOfBounds); +} + +LONGBOW_TEST_FIXTURE_SETUP(Errors) +{ + PARCDeque *deque = parcDeque_Create(); + longBowTestCase_SetClipBoardData(testCase, deque); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Errors) +{ + PARCDeque *deque = longBowTestCase_GetClipBoardData(testCase); + parcDeque_Release(&deque); + + 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_EXPECTS(Errors, parcDeque_GetAtIndex_OutOfBounds, .event = &LongBowTrapOutOfBounds) +{ + char *expected0 = "expected 1"; + char *expected1 = "expected 2"; + char *expected2 = "expected 3"; + + PARCDeque *deque = longBowTestCase_GetClipBoardData(testCase); + parcDeque_Append(deque, expected0); + parcDeque_Append(deque, expected1); + parcDeque_Append(deque, expected2); + + parcDeque_GetAtIndex(deque, 3); +} + +LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false) +{ + LONGBOW_RUN_TEST_CASE(Performance, parcQueue_Append); + LONGBOW_RUN_TEST_CASE(Performance, parcQueue_N2); + LONGBOW_RUN_TEST_CASE(Performance, parcQueue_Iterator); +} + +LONGBOW_TEST_FIXTURE_SETUP(Performance) +{ + parcMemory_SetInterface(&PARCStdlibMemoryAsPARCMemory); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Performance) +{ + 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(Performance, parcQueue_Append) +{ + PARCDeque *x = parcDeque_Create(); + + for (size_t i = 0; i < 100000; i++) { + parcDeque_Append(x, (void *) i); + } + + parcDeque_Release(&x); +} + +LONGBOW_TEST_CASE(Performance, parcQueue_N2) +{ + PARCDeque *x = parcDeque_Create(); + for (size_t i = 0; i < 100000; i++) { + parcDeque_Append(x, (void *) i); + } + + for (size_t expected = 0; expected < parcDeque_Size(x); expected++) { + size_t actual = (size_t) parcDeque_GetAtIndex(x, expected); + assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual); + } + + parcDeque_Release(&x); +} + +LONGBOW_TEST_CASE(Performance, parcQueue_Iterator) +{ + PARCDeque *x = parcDeque_Create(); + for (size_t i = 0; i < 100000; i++) { + parcDeque_Append(x, (void *) i); + } + + PARCIterator *iterator = parcDeque_Iterator(x); + size_t expected = 0; + while (parcIterator_HasNext(iterator)) { + size_t actual = (size_t) parcIterator_Next(iterator); + assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual); + expected++; + } + parcIterator_Release(&iterator); + + parcDeque_Release(&x); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Deque); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_Dictionary.c b/libparc/parc/algol/test/test_parc_Dictionary.c new file mode 100644 index 00000000..095f3c98 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_Dictionary.c @@ -0,0 +1,736 @@ +/* + * 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 <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +#include "../parc_Dictionary.c" + +static int * +_keyNewInt(int key) +{ + int *newKey = parcMemory_Allocate(sizeof(int)); + assertNotNull(newKey, "parcMemory_Allocate(%zu) returned NULL", + sizeof(int)); + *newKey = key; + return newKey; +} + +static int * +_valueNewInt(int value) +{ + int *newValue = parcMemory_Allocate(sizeof(int)); + assertNotNull(newValue, "parcMemory_Allocate(%zu) returned NULL", sizeof(int)); + *newValue = value; + return newValue; +} + +static bool +_valueEquals(const void *value1, const void *value2) +{ + return *(int *) value1 == *(int *) value2; +} + +static int +_intKeyComp(const void *key1, const void *key2) +{ + if (*(int *) key1 < *(int *) key2) { + return -1; + } + if (*(int *) key1 == *(int *) key2) { + return 0; + } + return 1; +} + +static uint32_t +_intKeyHash(const void *key1) +{ + return *(int *) key1; +} + + +static void +_keyFree(void **value) +{ + parcMemory_Deallocate((void **) value); + *value = NULL; +} + +static void +_valueFree(void **key) +{ + parcMemory_Deallocate((void **) key); + *key = NULL; +} + + + + +LONGBOW_TEST_RUNNER(PARC_Dictionary) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +LONGBOW_TEST_RUNNER_SETUP(PARC_Dictionary) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(PARC_Dictionary) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(-1); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Create); + LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_SetValue_Destroy); + LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Size_Empty); + LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Size); + LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Size_AfterDelete); + LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Size_AfterOverwrite); + LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Get_EmptyTree); + LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Get_NonExistent); + LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Get_First); + LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Get); + LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Get_Last); + LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Remove_First); + LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Remove); + LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Remove_Last); + LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_RemoveAndDestroy_First); + LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_RemoveAndDestroy); + LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_RemoveAndDestroy_Last); + LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Keys); + LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Values); + LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Equals_Empty); + LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Equals); + LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Equals_Not_Values); + LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Equals_Not_Keys); +} + +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, PARC_Dictionary_Create) +{ + PARCDictionary *dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, NULL, NULL, NULL); + + parcDictionary_Destroy(&dictionary); + + dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + + parcDictionary_Destroy(&dictionary); +} + +LONGBOW_TEST_CASE(Global, PARC_Dictionary_SetValue_Destroy) +{ + PARCDictionary *dictionary; + + dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + + parcDictionary_SetValue(dictionary, (void *) _keyNewInt(1), (void *) _valueNewInt(11)); + parcDictionary_SetValue(dictionary, (void *) _keyNewInt(2), (void *) _valueNewInt(12)); + parcDictionary_SetValue(dictionary, (void *) _keyNewInt(3), (void *) _valueNewInt(13)); + + parcDictionary_Destroy(&dictionary); +} + +LONGBOW_TEST_CASE(Global, PARC_Dictionary_Size_Empty) +{ + PARCDictionary *dictionary; + + dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + + assertTrue(0 == parcDictionary_Size(dictionary), "Wrong size of dictionary - empty, start"); + + parcDictionary_Destroy(&dictionary); +} + +LONGBOW_TEST_CASE(Global, PARC_Dictionary_Size) +{ + PARCDictionary *dictionary; + + dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + + parcDictionary_SetValue(dictionary, (void *) _keyNewInt(4), (void *) _valueNewInt(1004)); + parcDictionary_SetValue(dictionary, (void *) _keyNewInt(3), (void *) _valueNewInt(1003)); + parcDictionary_SetValue(dictionary, (void *) _keyNewInt(2), (void *) _valueNewInt(1002)); + parcDictionary_SetValue(dictionary, (void *) _keyNewInt(8), (void *) _valueNewInt(1008)); + + assertTrue(4 == parcDictionary_Size(dictionary), "Wrong size of dictionary after add 3"); + + parcDictionary_Destroy(&dictionary); +} + +LONGBOW_TEST_CASE(Global, PARC_Dictionary_Size_AfterDelete) +{ + PARCDictionary *dictionary; + + dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + + parcDictionary_SetValue(dictionary, (void *) _keyNewInt(4), (void *) _valueNewInt(1004)); + parcDictionary_SetValue(dictionary, (void *) _keyNewInt(3), (void *) _valueNewInt(1003)); + parcDictionary_SetValue(dictionary, (void *) _keyNewInt(2), (void *) _valueNewInt(1002)); + parcDictionary_SetValue(dictionary, (void *) _keyNewInt(8), (void *) _valueNewInt(1008)); + + int searchKey = 2; + + parcDictionary_RemoveAndDestroyValue(dictionary, &searchKey); + + size_t size = parcDictionary_Size(dictionary); + + assertTrue(3 == size, "Wrong size of dictionary after 1 delete (%zu instead of 3)", size); + + parcDictionary_Destroy(&dictionary); +} + +LONGBOW_TEST_CASE(Global, PARC_Dictionary_Size_AfterOverwrite) +{ + PARCDictionary *dictionary; + + dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + + parcDictionary_SetValue(dictionary, (void *) _keyNewInt(4), (void *) _valueNewInt(1004)); + parcDictionary_SetValue(dictionary, (void *) _keyNewInt(3), (void *) _valueNewInt(1003)); + parcDictionary_SetValue(dictionary, (void *) _keyNewInt(2), (void *) _valueNewInt(1002)); + parcDictionary_SetValue(dictionary, (void *) _keyNewInt(8), (void *) _valueNewInt(1008)); + + parcDictionary_SetValue(dictionary, (void *) _keyNewInt(3), (void *) _valueNewInt(1010)); + + size_t size = parcDictionary_Size(dictionary); + + assertTrue(4 == size, "Wrong size of dictionary after 1 delete (%zu instead of 4)", size); + + parcDictionary_Destroy(&dictionary); +} + +LONGBOW_TEST_CASE(Global, PARC_Dictionary_Get_EmptyTree) +{ + PARCDictionary *dictionary; + + int key = 100; + + dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + + void *value = parcDictionary_GetValue(dictionary, &key); + + assertTrue(NULL == value, "Object did not exist, must return NULL"); + + parcDictionary_Destroy(&dictionary); +} + +LONGBOW_TEST_CASE(Global, PARC_Dictionary_Get_NonExistent) +{ + PARCDictionary *dictionary; + int key = 100; + + dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + + for (int i = 1; i < 10; i++) { + // Add some elements to the dictionary + parcDictionary_SetValue(dictionary, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + } + + void *value = parcDictionary_GetValue(dictionary, &key); + + assertTrue(NULL == value, "Object did not exist, must return NULL"); + + parcDictionary_Destroy(&dictionary); +} + +LONGBOW_TEST_CASE(Global, PARC_Dictionary_Get_First) +{ + PARCDictionary *dictionary; + int key = 1; + + dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + + for (int i = 1; i < 10; i++) { + // Add some elements to the dictionary + parcDictionary_SetValue(dictionary, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + } + + int *value = parcDictionary_GetValue(dictionary, &key); + + assertNotNull(value, "NULL value returned"); + assertTrue(*value == (1 << 8), "Wrong object returned or not found"); + + parcDictionary_Destroy(&dictionary); +} + +LONGBOW_TEST_CASE(Global, PARC_Dictionary_Get) +{ + PARCDictionary *dictionary; + int key = 5; + + dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + + for (int i = 1; i < 10; i++) { + // Add some elements to the dictionary + parcDictionary_SetValue(dictionary, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + } + + int *value = parcDictionary_GetValue(dictionary, &key); + + assertNotNull(value, "NULL value returned"); + assertTrue(*value == (5 << 8), "Wrong object returned or not found"); + + parcDictionary_Destroy(&dictionary); +} + +LONGBOW_TEST_CASE(Global, PARC_Dictionary_Get_Last) +{ + PARCDictionary *dictionary; + int key = 9; + + dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + + for (int i = 1; i < 10; i++) { + // Add some elements to the dictionary + parcDictionary_SetValue(dictionary, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + } + + int *value = parcDictionary_GetValue(dictionary, &key); + + assertNotNull(value, "NULL value returned"); + assertTrue(*value == (9 << 8), "Wrong object returned or not found"); + + parcDictionary_Destroy(&dictionary); +} + +LONGBOW_TEST_CASE(Global, PARC_Dictionary_Remove_First) +{ + PARCDictionary *dictionary1; + PARCDictionary *dictionary2; + + dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + + for (int i = 30; i < 40; i++) { + // Add some elements to the dictionary + parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + } + parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(1), (void *) _valueNewInt(1 << 8)); + for (int i = 2; i < 10; i++) { + // Add some elements to the dictionary + parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + } + for (int i = 20; i < 30; i++) { + // Add some elements to the dictionary + parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + } + + int searchKey = 1; + + void *data = parcDictionary_RemoveValue(dictionary1, &searchKey); + + _valueFree(&data); + + assertTrue(parcDictionary_Equals(dictionary1, dictionary2), "Trees dont match after remove"); + + parcDictionary_Destroy(&dictionary1); + parcDictionary_Destroy(&dictionary2); +} + +LONGBOW_TEST_CASE(Global, PARC_Dictionary_Remove) +{ + PARCDictionary *dictionary1; + PARCDictionary *dictionary2; + + dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + + for (int i = 31; i < 40; i++) { + // Add some elements to the dictionary + parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + } + parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(30), (void *) _valueNewInt(31 << 8)); + for (int i = 2; i < 10; i++) { + // Add some elements to the dictionary + parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + } + for (int i = 20; i < 30; i++) { + // Add some elements to the dictionary + parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + } + + int searchKey = 30; + + void *data = parcDictionary_RemoveValue(dictionary1, &searchKey); + + _valueFree(&data); + + assertTrue(parcDictionary_Equals(dictionary1, dictionary2), "Trees dont match after remove"); + + parcDictionary_Destroy(&dictionary1); + parcDictionary_Destroy(&dictionary2); +} + +LONGBOW_TEST_CASE(Global, PARC_Dictionary_Remove_Last) +{ + PARCDictionary *dictionary1; + PARCDictionary *dictionary2; + + dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + + for (int i = 30; i < 40; i++) { + // Add some elements to the dictionary + parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + } + parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(100), (void *) _valueNewInt(100 << 8)); + for (int i = 2; i < 10; i++) { + // Add some elements to the dictionary + parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + } + for (int i = 20; i < 30; i++) { + // Add some elements to the dictionary + parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + } + + int searchKey = 100; + + void *data = parcDictionary_RemoveValue(dictionary1, &searchKey); + + _valueFree(&data); + + assertTrue(parcDictionary_Equals(dictionary1, dictionary2), "Trees dont match after remove"); + + parcDictionary_Destroy(&dictionary1); + parcDictionary_Destroy(&dictionary2); +} + +LONGBOW_TEST_CASE(Global, PARC_Dictionary_RemoveAndDestroy_First) +{ + PARCDictionary *dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + PARCDictionary *dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + + for (int i = 30; i < 40; i++) { + // Add some elements to the dictionary + parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + } + parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(1), (void *) _valueNewInt(1 << 8)); + for (int i = 2; i < 10; i++) { + // Add some elements to the dictionary + parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + } + for (int i = 20; i < 30; i++) { + // Add some elements to the dictionary + parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + } + + int searchKey = 1; + + parcDictionary_RemoveAndDestroyValue(dictionary1, &searchKey); + + assertTrue(parcDictionary_Equals(dictionary1, dictionary2), "Trees dont match after remove"); + + parcDictionary_Destroy(&dictionary1); + parcDictionary_Destroy(&dictionary2); +} + +LONGBOW_TEST_CASE(Global, PARC_Dictionary_RemoveAndDestroy) +{ + PARCDictionary *dictionary1; + PARCDictionary *dictionary2; + + dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + + for (int i = 31; i < 40; i++) { + // Add some elements to the dictionary + parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + } + parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(30), (void *) _valueNewInt(31 << 8)); + for (int i = 2; i < 10; i++) { + // Add some elements to the dictionary + parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + } + for (int i = 20; i < 30; i++) { + // Add some elements to the dictionary + parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + } + + int searchKey = 30; + + parcDictionary_RemoveAndDestroyValue(dictionary1, &searchKey); + + assertTrue(parcDictionary_Equals(dictionary1, dictionary2), "Trees dont match after remove"); + + parcDictionary_Destroy(&dictionary1); + parcDictionary_Destroy(&dictionary2); +} + +LONGBOW_TEST_CASE(Global, PARC_Dictionary_RemoveAndDestroy_Last) +{ + PARCDictionary *dictionary1; + PARCDictionary *dictionary2; + + dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + + for (int i = 30; i < 40; i++) { + // Add some elements to the dictionary + parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + } + parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(100), (void *) _valueNewInt(100 << 8)); + for (int i = 2; i < 10; i++) { + // Add some elements to the dictionary + parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + } + for (int i = 20; i < 30; i++) { + // Add some elements to the dictionary + parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + } + + int searchKey = 100; + + parcDictionary_RemoveAndDestroyValue(dictionary1, &searchKey); + + assertTrue(parcDictionary_Equals(dictionary1, dictionary2), "Trees dont match after remove"); + + parcDictionary_Destroy(&dictionary1); + parcDictionary_Destroy(&dictionary2); +} + +LONGBOW_TEST_CASE(Global, PARC_Dictionary_Keys) +{ + PARCDictionary *dictionary = + parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + + for (int i = 0; i < 9; i++) { + // Add some elements to the dictionary + parcDictionary_SetValue(dictionary, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + } + + PARCArrayList *keys = parcDictionary_Keys(dictionary); + + assertNotNull(keys, + "parcDictionary_Keys returned NULL, expected non-NULL."); + + assertTrue(parcArrayList_Size(keys) == parcDictionary_Size(dictionary), + "Expected parcDictionary_Keys size %zu, actual %zd, ", + parcDictionary_Size(dictionary), parcArrayList_Size(keys)); + + for (int i = 0; i < 9; i++) { + bool found = false; + int *keyToFind = _keyNewInt(i); + for (int j = 0; j < parcArrayList_Size(keys); j++) { + int *keyToTest = parcArrayList_Get(keys, j); + if (*keyToTest == *keyToFind) { + found = true; + break; + } + } + assertTrue(found, "Expected to find Key %d, not found", *keyToFind); + parcMemory_Deallocate((void **) &keyToFind); + } + parcArrayList_Destroy(&keys); + parcDictionary_Destroy(&dictionary); +} + +LONGBOW_TEST_CASE(Global, PARC_Dictionary_Values) +{ + PARCDictionary *dictionary = + parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + + for (int i = 0; i < 9; i++) { + // Add some elements to the dictionary + parcDictionary_SetValue(dictionary, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8)); + } + + PARCArrayList *values = parcDictionary_Values(dictionary); + + assertNotNull(values, + "parcDictionary_Values returned NULL, expected not NULL"); + + assertTrue(parcArrayList_Size(values) == parcDictionary_Size(dictionary), + "parcDictionary_Values size %zd not equal not parcDictionary_Size, %zd", + parcArrayList_Size(values), parcDictionary_Size(dictionary)); + + for (int i = 0; i < 9; i++) { + bool found = false; + int *keyToFind = _keyNewInt(i); + int *valueToFind = parcDictionary_GetValue(dictionary, keyToFind); + for (int j = 0; j < parcArrayList_Size(values); j++) { + int *valueToTest = parcArrayList_Get(values, j); + if (valueToFind == valueToTest) { + found = true; + break; + } + } + assertTrue(found, + "Expected to find value %d, not found", *valueToFind); + parcMemory_Deallocate((void **) &keyToFind); + } + parcArrayList_Destroy(&values); + parcDictionary_Destroy(&dictionary); +} + + +LONGBOW_TEST_CASE(Global, PARC_Dictionary_Equals_Empty) +{ + PARCDictionary *dictionary1; + PARCDictionary *dictionary2; + + dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + + assertTrue(parcDictionary_Equals(dictionary1, dictionary2), "Empty lists are not equal"); + + parcDictionary_Destroy(&dictionary1); + parcDictionary_Destroy(&dictionary2); +} + +LONGBOW_TEST_CASE(Global, PARC_Dictionary_Equals_Not_Values) +{ + PARCDictionary *dictionary1; + PARCDictionary *dictionary2; + + int compareSetValues = 100; + + dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + + printf("Testing dictionary equals...\n"); + + for (int i = 1; i < compareSetValues; i++) { + parcDictionary_SetValue(dictionary1, + (void *) _keyNewInt(i), + (void *) _valueNewInt(i << 8)); + parcDictionary_SetValue(dictionary2, + (void *) _keyNewInt(compareSetValues - i), + (void *) _valueNewInt((compareSetValues + i) << 8)); + } + + assertFalse(parcDictionary_Equals(dictionary1, dictionary2), "Dictionaries are equal and they shouldn't be!"); + + parcDictionary_Destroy(&dictionary1); + parcDictionary_Destroy(&dictionary2); +} + +LONGBOW_TEST_CASE(Global, PARC_Dictionary_Equals_Not_Keys) +{ + PARCDictionary *dictionary1; + PARCDictionary *dictionary2; + + int compareSetValues = 100; + + dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + + for (int i = 1; i < compareSetValues; i++) { + parcDictionary_SetValue(dictionary1, + (void *) _keyNewInt(i), + (void *) _valueNewInt(i << 8)); + parcDictionary_SetValue(dictionary2, + (void *) _keyNewInt(compareSetValues + i), + (void *) _valueNewInt((compareSetValues - i) << 8)); + } + + assertFalse(parcDictionary_Equals(dictionary1, dictionary2), "Lists are equal"); + + parcDictionary_Destroy(&dictionary1); + parcDictionary_Destroy(&dictionary2); +} + +LONGBOW_TEST_CASE(Global, PARC_Dictionary_Equals) +{ + PARCDictionary *dictionary1; + PARCDictionary *dictionary2; + + int compareSetValues = 100; + + dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree); + + for (int i = 1; i < compareSetValues; i++) { + parcDictionary_SetValue(dictionary1, + (void *) _keyNewInt(i), + (void *) _valueNewInt(i << 8)); + parcDictionary_SetValue(dictionary2, + (void *) _keyNewInt(compareSetValues - i), + (void *) _valueNewInt((compareSetValues - i) << 8)); + } + + assertTrue(parcDictionary_Equals(dictionary1, dictionary2), "Dictionaries are not equal"); + + parcDictionary_Destroy(&dictionary1); + parcDictionary_Destroy(&dictionary2); +} + +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[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(PARC_Dictionary); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_Display.c b/libparc/parc/algol/test/test_parc_Display.c new file mode 100755 index 00000000..29b9fdf2 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_Display.c @@ -0,0 +1,85 @@ +/* + * 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 "../parc_DisplayIndented.c" + +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(parc_Display) +{ + // 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(parc_Display) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_Display) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcDisplay_PrintLine); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, parcDisplay_PrintLine) +{ + testUnimplemented(""); +} + +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[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Display); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_Environment.c b/libparc/parc/algol/test/test_parc_Environment.c new file mode 100755 index 00000000..e4513b31 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_Environment.c @@ -0,0 +1,86 @@ +/* + * 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 "../parc_Environment.c" + +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(parc_Environment) +{ + // 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(parc_Environment) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_Environment) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcEnvironment_GetHomeDirectory); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, parcEnvironment_GetHomeDirectory) +{ + const char *homeDirectory = parcEnvironment_GetHomeDirectory(); + assertNotNull(homeDirectory, "Cannot get the current home directory."); +} + +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[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Environment); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_Event.c b/libparc/parc/algol/test/test_parc_Event.c new file mode 100644 index 00000000..261cd079 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_Event.c @@ -0,0 +1,243 @@ +/* + * 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 <LongBow/unit-test.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 "../parc_Event.c" + +LONGBOW_TEST_RUNNER(parc_Event) +{ + // 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(parc_Event) +{ + parcEvent_EnableDebug(); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_Event) +{ + parcEvent_DisableDebug(); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parc_Event_Create_Destroy); + LONGBOW_RUN_TEST_CASE(Global, parc_Event_Start); + LONGBOW_RUN_TEST_CASE(Global, parc_Event_Stop); + LONGBOW_RUN_TEST_CASE(Global, parc_Event_Poll); + LONGBOW_RUN_TEST_CASE(Global, parc_Event_SetPriority); +} + +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; +} + +static int _test_event_called = 0; + +static void +_test_event(int fd, PARCEventType flags, void *data) +{ + _test_event_called++; +} + +LONGBOW_TEST_CASE(Global, parc_Event_Create_Destroy) +{ + int fds[2]; + int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds); + assertFalse(result, "Socketpair creation failed.\n"); + + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + PARCEvent *parcEvent = parcEvent_Create(parcEventScheduler, fds[0], PARCEventType_Write, _test_event, NULL); + assertNotNull(parcEvent, "parcEvent_Create returned a null reference"); + parcEvent_Destroy(&parcEvent); + parcEventScheduler_Destroy(&parcEventScheduler); + + close(fds[0]); + close(fds[1]); +} + +LONGBOW_TEST_CASE(Global, parc_Event_Start) +{ + int fds[2]; + int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds); + assertFalse(result, "Socketpair creation failed.\n"); + + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + PARCEvent *parcEvent = parcEvent_Create(parcEventScheduler, fds[0], PARCEventType_Read | PARCEventType_Write, _test_event, NULL); + assertNotNull(parcEvent, "parcEvent_Create returned a null reference"); + + _test_event_called = 0; + parcEvent_Start(parcEvent); + parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking); + assertTrue(_test_event_called == 1, "Event never called."); + + parcEvent_Destroy(&parcEvent); + parcEventScheduler_Destroy(&parcEventScheduler); + close(fds[0]); + close(fds[1]); +} + +static int _test_stop_event_called = 0; + +static void +_test_stop_event(int fd, PARCEventType flags, void *data) +{ + PARCEvent **parcEvent = (PARCEvent **) data; + _test_stop_event_called++; + parcEvent_Stop(*parcEvent); +} + +LONGBOW_TEST_CASE(Global, parc_Event_Stop) +{ + int fds[2]; + int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds); + assertFalse(result, "Socketpair creation failed.\n"); + + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + PARCEvent *parcEvent = parcEvent_Create(parcEventScheduler, fds[0], PARCEventType_Write | PARCEventType_Persist, _test_stop_event, &parcEvent); + assertNotNull(parcEvent, "parcEvent_Create returned a null reference"); + + parcEvent_Start(parcEvent); + parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking); + assertTrue(_test_stop_event_called > 0, "Event never called."); + assertFalse(_test_stop_event_called != 1, "Event called more than once."); + + parcEvent_Destroy(&parcEvent); + parcEventScheduler_Destroy(&parcEventScheduler); + close(fds[0]); + close(fds[1]); +} + +LONGBOW_TEST_CASE(Global, parc_Event_Poll) +{ + int fds[2]; + int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds); + assertFalse(result, "Socketpair creation failed.\n"); + + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + PARCEvent *parcEvent = parcEvent_Create(parcEventScheduler, fds[0], PARCEventType_Write, _test_event, NULL); + assertNotNull(parcEvent, "parcEvent_Create returned a null reference"); + + result = parcEvent_Poll(parcEvent, PARCEventType_Read); + // should be no outstanding events + assertTrue(result == 0, "parcEvent_Poll returned %d\n", result); + + parcEvent_Destroy(&parcEvent); + parcEventScheduler_Destroy(&parcEventScheduler); + close(fds[0]); + close(fds[1]); +} + +static int _test_writeMaxPriority_event_called = 0; + +static void +_test_writeMaxPriority_event(int fd, PARCEventType flags, void *data) +{ + PARCEvent *parcEvent = *((PARCEvent **) data); + parcEvent_Stop(parcEvent); + _test_writeMaxPriority_event_called++; +} + +static int _test_writeMinPriority_event_called = 0; + +static void +_test_writeMinPriority_event(int fd, PARCEventType flags, void *data) +{ + PARCEvent *parcEvent = *((PARCEvent **) data); + parcEvent_Stop(parcEvent); + _test_writeMinPriority_event_called++; +} + +LONGBOW_TEST_CASE(Global, parc_Event_SetPriority) +{ + int fds[2]; + int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds); + assertFalse(result, "Socketpair creation failed.\n"); + + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + // + // First event to be called back disables its partner's event + // + PARCEvent *parcEventWriteMax, *parcEventWriteMin; + parcEventWriteMax = parcEvent_Create(parcEventScheduler, fds[0], + PARCEventType_Write, + _test_writeMaxPriority_event, + (void *) &parcEventWriteMin); + assertNotNull(parcEventWriteMax, "parcEvent_Create returned a null reference"); + parcEventWriteMin = parcEvent_Create(parcEventScheduler, fds[1], + PARCEventType_Write, + _test_writeMinPriority_event, + (void *) &parcEventWriteMax); + assertNotNull(parcEventWriteMin, "parcEvent_Create returned a null reference"); + + result = parcEvent_SetPriority(parcEventWriteMin, PARCEventPriority_Minimum); + assertTrue(result == 0, "parcEvent_SetPriority write returned %d\n", result); + result = parcEvent_SetPriority(parcEventWriteMax, PARCEventPriority_Maximum); + assertTrue(result == 0, "parcEvent_SetPriority read returned %d\n", result); + + parcEvent_Start(parcEventWriteMin); + parcEvent_Start(parcEventWriteMax); + + parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_NonBlocking); + + assertTrue(_test_writeMaxPriority_event_called == 1, "Read event called before priority write event handled"); + assertTrue(_test_writeMinPriority_event_called == 0, "Write event never triggered"); + + parcEvent_Destroy(&parcEventWriteMax); + parcEvent_Destroy(&parcEventWriteMin); + parcEventScheduler_Destroy(&parcEventScheduler); + close(fds[0]); + close(fds[1]); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Event); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_EventBuffer.c b/libparc/parc/algol/test/test_parc_EventBuffer.c new file mode 100644 index 00000000..c0b8d8c9 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_EventBuffer.c @@ -0,0 +1,345 @@ +/* + * 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 <pthread.h> + +#include <arpa/inet.h> + +#include <LongBow/unit-test.h> + +#include <parc/algol/parc_SafeMemory.h> +#include <parc/algol/parc_EventBuffer.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../parc_EventBuffer.c" + +LONGBOW_TEST_RUNNER(parc_EventBuffer) +{ + // 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(parc_EventBuffer) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_EventBuffer) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_Create_Destroy); + LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_GetLength_Append); + LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_Prepend_Pullup); + LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_ReadIntoBuffer); + LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_AppendBuffer); + LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_Read); + LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_WriteToFileDescriptor); + LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_ReadFromFileDescriptor); + LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_ReadLine_FreeLine); + LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_GetQueueBuffer); +} + +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, parc_EventBuffer_Create_Destroy) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler)); + + PARCEventBuffer *parcEventBuffer = parcEventBuffer_Create(); + assertNotNull(parcEventBuffer, "parcEventBuffer_Create returned a null reference"); + + parcEventBuffer_Destroy(&parcEventBuffer); + parcEventScheduler_Destroy(&parcEventScheduler); + parcEventBuffer_DisableDebug(); +} + +static int _dataLength = 8192; + +LONGBOW_TEST_CASE(Global, parc_EventBuffer_GetLength_Append) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler)); + + PARCEventBuffer *parcEventBuffer = parcEventBuffer_Create(); + assertNotNull(parcEventBuffer, "parcEventBuffer_Create returned a null reference"); + + char data[_dataLength]; + parcEventBuffer_Append(parcEventBuffer, data, _dataLength); + assertTrue(parcEventBuffer_GetLength(parcEventBuffer) == _dataLength, "Buffer length does not match length of appended data"); + + parcEventBuffer_Destroy(&parcEventBuffer); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +static uint8_t prependedDataValue = '1'; + +LONGBOW_TEST_CASE(Global, parc_EventBuffer_Prepend_Pullup) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler)); + + PARCEventBuffer *parcEventBuffer = parcEventBuffer_Create(); + assertNotNull(parcEventBuffer, "parcEventBuffer_Create returned a null reference"); + + char data[_dataLength]; + data[0] = 2; + parcEventBuffer_Append(parcEventBuffer, data, _dataLength); + assertTrue(parcEventBuffer_GetLength(parcEventBuffer) == _dataLength, "Buffer length does not match length of appended data"); + + uint8_t prependedData[1]; + prependedData[0] = prependedDataValue; + parcEventBuffer_Prepend(parcEventBuffer, prependedData, sizeof(uint8_t)); + size_t bufferSize = parcEventBuffer_GetLength(parcEventBuffer); + assertTrue(bufferSize == (_dataLength + 1), "Buffer length does not match length plus prepended data length"); + + uint8_t *completeBuffer = parcEventBuffer_Pullup(parcEventBuffer, -1); + assertTrue(completeBuffer[0] == prependedDataValue, "Prepended data doesn't match %d != %d", completeBuffer[0], prependedDataValue); + assertTrue(completeBuffer[1] == 2, "Consolidated data doesn't match %d != %d", completeBuffer[1], 2); + + parcEventBuffer_Destroy(&parcEventBuffer); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +LONGBOW_TEST_CASE(Global, parc_EventBuffer_ReadIntoBuffer) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler)); + + PARCEventBuffer *parcEventBufferSource = parcEventBuffer_Create(); + assertNotNull(parcEventBufferSource, "parcEventBuffer_Create returned a null reference"); + char sourceData[_dataLength]; + parcEventBuffer_Append(parcEventBufferSource, sourceData, _dataLength); + + PARCEventBuffer *parcEventBufferDestination = parcEventBuffer_Create(); + assertNotNull(parcEventBufferDestination, "parcEventBuffer_Create returned a null reference"); + char destinationData[_dataLength]; + parcEventBuffer_Append(parcEventBufferDestination, destinationData, _dataLength); + + parcEventBuffer_ReadIntoBuffer(parcEventBufferSource, parcEventBufferDestination, -1); + size_t bufferSize = parcEventBuffer_GetLength(parcEventBufferDestination); + assertTrue(bufferSize == (_dataLength * 2), "Destination buffer size doesn't match expected length"); + + parcEventBuffer_Destroy(&parcEventBufferSource); + parcEventBuffer_Destroy(&parcEventBufferDestination); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +LONGBOW_TEST_CASE(Global, parc_EventBuffer_AppendBuffer) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler)); + + PARCEventBuffer *parcEventBufferSource = parcEventBuffer_Create(); + assertNotNull(parcEventBufferSource, "parcEventBuffer_Create returned a null reference"); + char sourceData[_dataLength]; + parcEventBuffer_Append(parcEventBufferSource, sourceData, _dataLength); + + PARCEventBuffer *parcEventBufferDestination = parcEventBuffer_Create(); + assertNotNull(parcEventBufferDestination, "parcEventBuffer_Create returned a null reference"); + char destinationData[_dataLength]; + parcEventBuffer_Append(parcEventBufferDestination, destinationData, _dataLength); + + parcEventBuffer_AppendBuffer(parcEventBufferSource, parcEventBufferDestination); + size_t bufferSize = parcEventBuffer_GetLength(parcEventBufferDestination); + assertTrue(bufferSize == (_dataLength * 2), "Destination buffer size doesn't match expected length, %zu != %d", bufferSize, _dataLength * 2); + + parcEventBuffer_Destroy(&parcEventBufferSource); + parcEventBuffer_Destroy(&parcEventBufferDestination); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +LONGBOW_TEST_CASE(Global, parc_EventBuffer_Read) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler)); + + PARCEventBuffer *parcEventBuffer = parcEventBuffer_Create(); + assertNotNull(parcEventBuffer, "parcEventBuffer_Create returned a null reference"); + + char sourceData[64] = "This is a test"; + parcEventBuffer_Append(parcEventBuffer, sourceData, 64); + + char readDataBuffer[64]; + int length = parcEventBuffer_Read(parcEventBuffer, readDataBuffer, 32); + + assertTrue(strncmp(sourceData, readDataBuffer, 32) == 0, + "Buffer contents written do not match contents read"); + assertTrue(length == 32, "parcEventBuffer_Read length unexpected %d != 32\n", length); + + length = parcEventBuffer_Read(parcEventBuffer, NULL, 64); + assertTrue(length == 0, "Drain of parcEventBuffer returned %d", length); + + parcEventBuffer_Destroy(&parcEventBuffer); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +LONGBOW_TEST_CASE(Global, parc_EventBuffer_WriteToFileDescriptor) +{ + int fds[2]; + int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds); + assertFalse(result, "Socketpair creation failed.\n"); + + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler)); + + PARCEventBuffer *parcEventBuffer = parcEventBuffer_Create(); + assertNotNull(parcEventBuffer, "parcEventBuffer_Create returned a null reference"); + + char sourceData[100] = "This is a test"; + parcEventBuffer_Append(parcEventBuffer, sourceData, 64); + size_t written = parcEventBuffer_WriteToFileDescriptor(parcEventBuffer, fds[0], 64); + + assertTrue(written == 64, "Length written does not match buffer length."); + assertTrue(read(fds[1], sourceData, 100) == 64, "Length read does not match length written."); + + parcEventBuffer_Destroy(&parcEventBuffer); + parcEventScheduler_Destroy(&parcEventScheduler); + close(fds[0]); + close(fds[1]); +} + +LONGBOW_TEST_CASE(Global, parc_EventBuffer_ReadFromFileDescriptor) +{ + int fds[2]; + int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds); + assertFalse(result, "Socketpair creation failed.\n"); + + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler)); + + PARCEventBuffer *parcEventBuffer = parcEventBuffer_Create(); + assertNotNull(parcEventBuffer, "parcEventBuffer_Create returned a null reference"); + + char sourceData[64] = "This is a test"; + parcEventBuffer_Append(parcEventBuffer, sourceData, 64); + + size_t written = parcEventBuffer_WriteToFileDescriptor(parcEventBuffer, fds[0], 64); + assertTrue(written == 64, "Length written does not match buffer length."); + size_t read = parcEventBuffer_ReadFromFileDescriptor(parcEventBuffer, fds[1], -1); + + assertTrue(read == 64, "Length read does not match amount written."); + + parcEventBuffer_Destroy(&parcEventBuffer); + parcEventScheduler_Destroy(&parcEventScheduler); + close(fds[0]); + close(fds[1]); +} + +LONGBOW_TEST_CASE(Global, parc_EventBuffer_ReadLine_FreeLine) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler)); + + PARCEventBuffer *parcEventBuffer = parcEventBuffer_Create(); + assertNotNull(parcEventBuffer, "parcEventBuffer_Create returned a null reference"); + + char sourceData[64] = "This is a test\n"; + parcEventBuffer_Append(parcEventBuffer, sourceData, 64); + assertTrue(parcEventBuffer_GetLength(parcEventBuffer) == 64, "parcEventBuffer has wrong length %zu.", parcEventBuffer_GetLength(parcEventBuffer)); + + size_t bytesRead; + char *lineRead = parcEventBuffer_ReadLine(parcEventBuffer, &bytesRead); + // read up to newline and terminate, so we read the newline but don't return it in the result + assertTrue(parcEventBuffer_GetLength(parcEventBuffer) == (64 - (bytesRead + 1)), + "parcEventBuffer has wrong length %zu != %zu.", + (64 - (bytesRead + 1)), parcEventBuffer_GetLength(parcEventBuffer)); + assertTrue(strncmp(sourceData, lineRead, bytesRead) == 0, "Line read doesn't match %s != %s", sourceData, lineRead); + assertTrue((strlen(sourceData) - strlen(lineRead)) == 1, "Line length doesn't match %zu != %zu", strlen(sourceData), strlen(lineRead)); + + parcEventBuffer_FreeLine(parcEventBuffer, &lineRead); + + parcEventBuffer_Destroy(&parcEventBuffer); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +LONGBOW_TEST_CASE(Global, parc_EventBuffer_GetQueueBuffer) +{ + int fds[2]; + int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds); + assertFalse(result, "Socketpair creation failed.\n"); + + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler)); + + PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, fds[0], 0); + assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference"); + + PARCEventBuffer *parcEventBuffer_Output = parcEventBuffer_GetQueueBufferOutput(parcEventQueue); + assertNotNull(parcEventBuffer_Output, "Received null output buffer from queue"); + + PARCEventBuffer *parcEventBuffer_Input = parcEventBuffer_GetQueueBufferInput(parcEventQueue); + assertNotNull(parcEventBuffer_Input, "Received null input buffer from queue"); + + parcEventBuffer_Destroy(&parcEventBuffer_Output); + parcEventBuffer_Destroy(&parcEventBuffer_Input); + parcEventQueue_Destroy(&parcEventQueue); + parcEventScheduler_Destroy(&parcEventScheduler); + close(fds[0]); + close(fds[1]); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_EventBuffer); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_EventQueue.c b/libparc/parc/algol/test/test_parc_EventQueue.c new file mode 100644 index 00000000..862cb61d --- /dev/null +++ b/libparc/parc/algol/test/test_parc_EventQueue.c @@ -0,0 +1,402 @@ +/* + * 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 <pthread.h> + +#include <arpa/inet.h> + +#include <LongBow/unit-test.h> + +#include <parc/algol/parc_SafeMemory.h> +#include <parc/algol/parc_EventQueue.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../parc_EventQueue.c" + +LONGBOW_TEST_RUNNER(parc_EventQueue) +{ + // 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(parc_EventQueue) +{ + parcEventQueue_EnableDebug(); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_EventQueue) +{ + parcEventQueue_DisableDebug(); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_Create_Destroy); + LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_SetFileDescriptor_GetFileDecriptor); + LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_Get_Enable_Disable); + LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_SetCallbacks); + LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_Flush); + LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_Finished); + LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_SetWatermark); + LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_ReadWrite); + LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_SetPriority); + LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_Printf); + LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_GetEvBuffer); + LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_ConnectSocket); + LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_Create_Destroy_Pair); + LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_GetUpDownQueue); +} + +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, parc_EventQueue_Create_Destroy) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0); + assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference"); + + parcEventQueue_Destroy(&parcEventQueue); + assertNull(parcEventQueue, "parcEventQueue_Destroy did not clear reference"); + parcEventScheduler_Destroy(&parcEventScheduler); + assertNull(parcEventScheduler, "parcEventScheduler_Destroy did not clear reference"); +} + +LONGBOW_TEST_CASE(Global, parc_EventQueue_Get_Enable_Disable) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0); + assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference"); + + PARCEventType defaultEvents = parcEventQueue_GetEnabled(parcEventQueue); + + parcEventQueue_Enable(parcEventQueue, PARCEventType_Read); + PARCEventType newEvents = parcEventQueue_GetEnabled(parcEventQueue); + assertTrue(newEvents == (defaultEvents | PARCEventType_Read), + "parcEventQueue_GetEnabled returned incorrect event set 0x%x != 0x%x", + newEvents, defaultEvents | PARCEventType_Read); + + parcEventQueue_Disable(parcEventQueue, PARCEventType_Read); + + newEvents = parcEventQueue_GetEnabled(parcEventQueue); + assertTrue(defaultEvents == newEvents, "parcEventQueue_GetEnabled returned incorrect event set 0x%x != 0x%x", newEvents, defaultEvents); + + parcEventQueue_Destroy(&parcEventQueue); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +LONGBOW_TEST_CASE(Global, parc_EventQueue_SetFileDescriptor_GetFileDecriptor) +{ + int fds[2]; + int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds); + assertFalse(result, "Socketpair creation failed.\n"); + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0); + assertNotNull(parcEventQueue, "parcEventQueue_Create returned null"); + + result = parcEventQueue_SetFileDescriptor(parcEventQueue, fds[0]); + assertTrue(result == 0, " parcEventQueue_SetFileDescriptor call failed"); + + result = parcEventQueue_GetFileDescriptor(parcEventQueue); + assertTrue(result == fds[0], "parcEventQueue_GetFileDescriptor failed"); + + parcEventQueue_Destroy(&parcEventQueue); + parcEventScheduler_Destroy(&parcEventScheduler); + close(fds[0]); + close(fds[1]); +} + +LONGBOW_TEST_CASE(Global, parc_EventQueue_Create_Destroy_Pair) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned null"); + + PARCEventQueuePair *parcEventQueuePair = parcEventQueue_CreateConnectedPair(parcEventScheduler); + assertNotNull(parcEventQueuePair, "parcEventQueue_CreateConnectedPair returned a null pair"); + + parcEventQueue_DestroyConnectedPair(&parcEventQueuePair); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +LONGBOW_TEST_CASE(Global, parc_EventQueue_GetUpDownQueue) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + + PARCEventQueuePair *parcEventQueuePair = parcEventQueue_CreateConnectedPair(parcEventScheduler); + + assertNotNull(parcEventQueue_GetConnectedUpQueue(parcEventQueuePair), "parcEventQueue_GetUpQueue returned null"); + assertNotNull(parcEventQueue_GetConnectedDownQueue(parcEventQueuePair), "parcEventQueue_GetDownQueue returned null"); + + parcEventQueue_DestroyConnectedPair(&parcEventQueuePair); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +static int _queue_callback_count = 0; + +static void +_queue_callback(PARCEventQueue *event, PARCEventType type, void *data) +{ + _queue_callback_count++; +} + +static int _queue_event_callback_count = 0; + +static void +_queue_event_callback(PARCEventQueue *event, PARCEventQueueEventType type, void *data) +{ + _queue_event_callback_count++; +} + +LONGBOW_TEST_CASE(Global, parc_EventQueue_SetCallbacks) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0); + assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference"); + + parcEventQueue_SetCallbacks(parcEventQueue, + _queue_callback, + _queue_callback, + _queue_event_callback, + NULL); + + _parc_queue_read_callback(NULL, parcEventQueue); + assertTrue(_queue_callback_count == 1, "Callback count expected 1 got %d", _queue_callback_count); + + _parc_queue_write_callback(NULL, parcEventQueue); + assertTrue(_queue_callback_count == 2, "Callback count expected 2 got %d", _queue_callback_count); + + _parc_queue_event_callback(NULL, PARCEventQueueEventType_EOF, parcEventQueue); + assertTrue(_queue_event_callback_count == 1, "Callback event count expected 1 got %d", _queue_event_callback_count); + + parcEventQueue_Destroy(&parcEventQueue); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +LONGBOW_TEST_CASE(Global, parc_EventQueue_Flush) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0); + assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference"); + + int result = parcEventQueue_Flush(parcEventQueue, PARCEventType_Read); + assertTrue(result == 0, "parcEventQueue_Flush failed with %d", result); + + parcEventQueue_Destroy(&parcEventQueue); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +LONGBOW_TEST_CASE(Global, parc_EventQueue_Finished) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0); + assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference"); + + int result = parcEventQueue_Finished(parcEventQueue, PARCEventType_Read); + assertTrue(result == 0, "parcEventQueue_Finished failed with %d", result); + + parcEventQueue_Destroy(&parcEventQueue); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +LONGBOW_TEST_CASE(Global, parc_EventQueue_SetWatermark) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0); + assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference"); + + parcEventQueue_SetWatermark(parcEventQueue, PARCEventType_Read, 0, 0); + + parcEventQueue_Destroy(&parcEventQueue); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +LONGBOW_TEST_CASE(Global, parc_EventQueue_ReadWrite) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0); + assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference"); + + char *data = "Hello World\n"; + int length = strlen(data); + int result = parcEventQueue_Write(parcEventQueue, data, length); + assertTrue(result == 0, "parcEventQueue_Write failed."); + + char buffer[64]; + result = parcEventQueue_Read(parcEventQueue, buffer, 64); + assertTrue(result == 0, "parcEventQueue_Read failed."); + + parcEventQueue_Destroy(&parcEventQueue); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +static int _test_writeMaxPriority_event_called = 0; +static void +_test_writeMaxPriority_callback(PARCEventQueue *parcEventQueue, PARCEventType event, void *data) +{ + PARCEventQueue *parcEventQueuePartner = *((PARCEventQueue **) data); + parcEventQueue_Disable(parcEventQueuePartner, event); + _test_writeMaxPriority_event_called++; +} + +static int _test_writeMinPriority_event_called = 0; +static void +_test_writeMinPriority_callback(PARCEventQueue *parcEventQueue, PARCEventType event, void *data) +{ + PARCEventQueue *parcEventQueuePartner = *((PARCEventQueue **) data); + parcEventQueue_Disable(parcEventQueuePartner, event); + _test_writeMinPriority_event_called++; +} + +LONGBOW_TEST_CASE(Global, parc_EventQueue_SetPriority) +{ + int fds[2]; + int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds); + assertFalse(result, "Socketpair creation failed.\n"); + + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + // + // First queue to be called back disables its partner's queue + // + PARCEventQueue *parcEventQueueMin, *parcEventQueueMax; + parcEventQueueMin = parcEventQueue_Create(parcEventScheduler, fds[0], PARCEventQueueOption_CloseOnFree); + assertNotNull(parcEventQueueMin, "parcEventQueue_Create returned a null reference"); + parcEventQueue_SetCallbacks(parcEventQueueMin, NULL, _test_writeMinPriority_callback, NULL, (void *) &parcEventQueueMax); + + parcEventQueueMax = parcEventQueue_Create(parcEventScheduler, fds[0], PARCEventQueueOption_CloseOnFree); + assertNotNull(parcEventQueueMax, "parcEventQueue_Create returned a null reference"); + parcEventQueue_SetCallbacks(parcEventQueueMax, NULL, _test_writeMaxPriority_callback, NULL, (void *) &parcEventQueueMin); + + result = parcEventQueue_SetPriority(parcEventQueueMin, PARCEventPriority_Minimum); + assertTrue(result == 0, "parcEventQueue_SetPriority Minimum priority failed."); + result = parcEventQueue_SetPriority(parcEventQueueMax, PARCEventPriority_Maximum); + assertTrue(result == 0, "parcEventQueue_SetPriority Maximum priority failed."); + + parcEventQueue_Enable(parcEventQueueMin, PARCEventType_Write); + parcEventQueue_Enable(parcEventQueueMax, PARCEventType_Write); + + parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_NonBlocking); + + assertTrue(_test_writeMaxPriority_event_called == 1, "Read event called before priority write event handled"); + assertTrue(_test_writeMinPriority_event_called == 0, "Write event never triggered"); + + parcEventQueue_Destroy(&parcEventQueueMin); + parcEventQueue_Destroy(&parcEventQueueMax); + parcEventScheduler_Destroy(&parcEventScheduler); + close(fds[0]); + close(fds[1]); +} + +LONGBOW_TEST_CASE(Global, parc_EventQueue_Printf) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0); + assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference"); + + int result = parcEventQueue_Printf(parcEventQueue, "%s %s\n", "Hello", "World"); + assertTrue(result == 12, "parcEventQueue_Printf didn't write expected length %d != %d", result, 12); + + parcEventQueue_Destroy(&parcEventQueue); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +LONGBOW_TEST_CASE(Global, parc_EventQueue_GetEvBuffer) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0); + assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference"); + + struct evbuffer *result = internal_parcEventQueue_GetEvInputBuffer(parcEventQueue); + assertTrue(result != NULL, "parcEventQueue_GetEvInputBuffer failed."); + + result = internal_parcEventQueue_GetEvOutputBuffer(parcEventQueue); + assertTrue(result != NULL, "parcEventQueue_GetEvOutputBuffer failed."); + + parcEventQueue_Destroy(&parcEventQueue); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +LONGBOW_TEST_CASE(Global, parc_EventQueue_ConnectSocket) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, -1, 0); + assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference"); + + struct sockaddr_in address; + int addressLength = sizeof(address); + memset(&address, 0, addressLength); + address.sin_family = AF_INET; + address.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */ + address.sin_port = htons(8080); /* Port 8080 */ + + int result = parcEventQueue_ConnectSocket(parcEventQueue, (struct sockaddr *) &address, addressLength); + assertTrue(result == 0, "parcEventQueue_ConnectSocket returned %d", result); + + parcEventQueue_Destroy(&parcEventQueue); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_EventQueue); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_EventScheduler.c b/libparc/parc/algol/test/test_parc_EventScheduler.c new file mode 100755 index 00000000..8195bd2e --- /dev/null +++ b/libparc/parc/algol/test/test_parc_EventScheduler.c @@ -0,0 +1,263 @@ +/* + * 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 <pthread.h> + +#include <LongBow/unit-test.h> + +#include "../internal_parc_Event.h" +#include <parc/algol/parc_SafeMemory.h> +#include <parc/algol/parc_EventScheduler.h> +#include <parc/algol/parc_EventTimer.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../parc_EventScheduler.c" + +LONGBOW_TEST_RUNNER(parc_EventScheduler) +{ + // 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(parc_EventScheduler) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_EventScheduler) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parc_EventScheduler_Create_Destroy); + LONGBOW_RUN_TEST_CASE(Global, parc_EventScheduler_Run); + LONGBOW_RUN_TEST_CASE(Global, parc_EventScheduler_Dispatch); + LONGBOW_RUN_TEST_CASE(Global, parc_EventScheduler_Stop); + LONGBOW_RUN_TEST_CASE(Global, parc_EventScheduler_Abort); + LONGBOW_RUN_TEST_CASE(Global, parc_EventScheduler_Memory); + LONGBOW_RUN_TEST_CASE(Global, parc_EventScheduler_GetEvBase); + LONGBOW_RUN_TEST_CASE(Global, parc_EventScheduler_GetLogger); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + parcEventScheduler_EnableDebug(); + 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; + } + + parcEventScheduler_DisableDebug(); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, parc_EventScheduler_Create_Destroy) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + parcEventScheduler_Destroy(&parcEventScheduler); + assertNull(parcEventScheduler, "parcEventScheduler_Destroy failed to null reference"); +} + +static void +_event_callback(int fd, PARCEventType flags, void *data) +{ + (*(unsigned *) data)++; +} + +static int _callback_event_called = 0; + +LONGBOW_TEST_CASE(Global, parc_EventScheduler_Run) +{ + _callback_event_called = 0; + + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + PARCEventTimer *parcEvent = parcEventTimer_Create(parcEventScheduler, 0, _event_callback, (void *) &_callback_event_called); + assertNotNull(parcEvent, "parcEventTimer_Create returned a null reference"); + + struct timeval fs = { 0, 1 }; + parcEventTimer_Start(parcEvent, &fs); + + parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking); + assertTrue(_callback_event_called == 1, "Timer event never called back"); + + parcEventTimer_Destroy(&parcEvent); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +LONGBOW_TEST_CASE(Global, parc_EventScheduler_Dispatch) +{ + _callback_event_called = 0; + + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + PARCEventTimer *parcEvent = parcEventTimer_Create(parcEventScheduler, 0, _event_callback, (void *) &_callback_event_called); + assertNotNull(parcEvent, "parcEventTimer_Create returned a null reference"); + + struct timeval fs = { 0, 1 }; + parcEventTimer_Start(parcEvent, &fs); + + // This will block until the event is processed + parcEventScheduler_DispatchBlocking(parcEventScheduler); + assertTrue(_callback_event_called == 1, "Timer event never called back"); + + // Start the timer + struct timeval longerfs = { 1, 0 }; // 1s + parcEventTimer_Start(parcEvent, &longerfs); + parcEventScheduler_DispatchNonBlocking(parcEventScheduler); + assertTrue(_callback_event_called == 1, "Timer event called again prematurely"); + usleep(2000000); // 2s + parcEventScheduler_DispatchNonBlocking(parcEventScheduler); + assertTrue(_callback_event_called == 2, "Timer event never called back"); + + parcEventTimer_Destroy(&parcEvent); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +static void +_stop_callback(int fd, PARCEventType flags, void *data) +{ + PARCEventScheduler *parcEventScheduler = (PARCEventScheduler *) data; + struct timeval fs = { 0, 0 }; + parcEventScheduler_Stop(parcEventScheduler, &fs); + _callback_event_called++; +} + +LONGBOW_TEST_CASE(Global, parc_EventScheduler_Stop) +{ + _callback_event_called = 0; + + // Create a new scheduler + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + // Create a persistent event which will repeat until stopped + PARCEventTimer *parcEvent = parcEventTimer_Create(parcEventScheduler, PARCEventType_Persist, _stop_callback, parcEventScheduler); + assertNotNull(parcEvent, "parcEventTimer_Create returned a null reference"); + + struct timeval fs = { 1, 0 }; + parcEventTimer_Start(parcEvent, &fs); + + parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking); + assertTrue(_callback_event_called == 1, "Timer event never called back"); + + parcEventTimer_Destroy(&parcEvent); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +static void +_abort_callback(int fd, PARCEventType flags, void *data) +{ + PARCEventScheduler *parcEventScheduler = (PARCEventScheduler *) data; + parcEventScheduler_Abort(parcEventScheduler); +} + +LONGBOW_TEST_CASE(Global, parc_EventScheduler_Abort) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + PARCEventTimer *parcEvent = parcEventTimer_Create(parcEventScheduler, PARCEventType_Persist, _abort_callback, parcEventScheduler); + assertNotNull(parcEvent, "parcEventTimer_Create returned a null reference"); + + struct timeval fs = { 1, 0 }; + parcEventTimer_Start(parcEvent, &fs); + + parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking); + + parcEventTimer_Destroy(&parcEvent); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +static void +_test_memory_event(int fd, short flags, void *data) +{ +} + +/** + * Ensure that the scheduler is using parc memory inside libevent + */ +LONGBOW_TEST_CASE(Global, parc_EventScheduler_Memory) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + size_t baseline = parcMemory_Outstanding(); + + struct event *testEvent = event_new(parcEventScheduler_GetEvBase(parcEventScheduler), -1, 0, _test_memory_event, NULL); + + assertTrue(parcMemory_Outstanding() > baseline, + "event_new() did not increase parcMemory_Outstanding: baseline %zu now %u", + baseline, + parcMemory_Outstanding()); + + event_free(testEvent); + + assertTrue(parcMemory_Outstanding() == baseline, + "event_free() did reduce to baseline: baseline %zu now %u", + baseline, + parcMemory_Outstanding()); + + parcEventScheduler_Destroy(&parcEventScheduler); + + assertTrue(parcSafeMemory_ReportAllocation(STDOUT_FILENO) == 0, "Memory imbalance on create/destroy: %u", parcMemory_Outstanding()); +} + +LONGBOW_TEST_CASE(Global, parc_EventScheduler_GetEvBase) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + assertNotNull(parcEventScheduler_GetEvBase(parcEventScheduler), "Expected a non-null EV pointer."); + + parcEventScheduler_Destroy(&parcEventScheduler); +} + +LONGBOW_TEST_CASE(Global, parc_EventScheduler_GetLogger) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + assertNotNull(parcEventScheduler_GetLogger(parcEventScheduler), "Expected a non-null logger."); + + parcEventScheduler_Destroy(&parcEventScheduler); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_EventScheduler); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_EventSignal.c b/libparc/parc/algol/test/test_parc_EventSignal.c new file mode 100644 index 00000000..fcb86333 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_EventSignal.c @@ -0,0 +1,167 @@ +/* + * 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 <pthread.h> + +#include <LongBow/unit-test.h> + +#include <parc/algol/parc_SafeMemory.h> +#include <parc/algol/parc_EventSignal.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../parc_EventSignal.c" + +LONGBOW_TEST_RUNNER(parc_EventSignal) +{ + // 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(parc_EventSignal) +{ + parcEventSignal_EnableDebug(); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_EventSignal) +{ + parcEventSignal_DisableDebug(); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parc_EventSignal_Create_Destroy); + LONGBOW_RUN_TEST_CASE(Global, parc_EventSignal_Start_Stop); +} + +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; +} + +static int _empty_event_called = 0; + +static void +_empty_event(int fd, PARCEventType flags, void *data) +{ + _empty_event_called++; +} + +LONGBOW_TEST_CASE(Global, parc_EventSignal_Create_Destroy) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + PARCEventSignal *parcEventSignal = parcEventSignal_Create(parcEventScheduler, SIGUSR1, PARCEventType_Signal | PARCEventType_Persist, _empty_event, NULL); + assertNotNull(parcEventSignal, "parcEventSignal_Create returned a null reference"); + + _parc_event_signal_callback(0, 0, (void *) parcEventSignal); + assertTrue(_empty_event_called == 1, "Event handler never called."); + parcEventSignal_Destroy(&parcEventSignal); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +#include <pthread.h> + +static void * +_run_scheduler(void *data) +{ + PARCEventScheduler *parcEventScheduler = (PARCEventScheduler *) data; + parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking); + return NULL; +} + +static int _test_event_called = 0; + +static void +_signal_event(int fd, PARCEventType flags, void *data) +{ + PARCEventSignal **parcEventSignal = (PARCEventSignal **) data; + _test_event_called++; + parcEventSignal_Stop(*parcEventSignal); +} + +LONGBOW_TEST_CASE(Global, parc_EventSignal_Start_Stop) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + PARCEventSignal *parcEventSignal = parcEventSignal_Create(parcEventScheduler, SIGUSR1, PARCEventType_Signal | PARCEventType_Persist, _signal_event, &parcEventSignal); + assertNotNull(parcEventSignal, "parcEventSignal_Create returned a null reference"); + + parcEventSignal_Start(parcEventSignal); + + pthread_t thread; + pthread_create(&thread, NULL, _run_scheduler, parcEventScheduler); + + kill(getpid(), SIGUSR1); + pthread_join(thread, NULL); + assertTrue(_test_event_called == 1, "Event never called."); + + parcEventSignal_Destroy(&parcEventSignal); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +static void +_test_stop_event(int fd, PARCEventType flags, void *data) +{ + PARCEventSignal **parcEventSignal = (PARCEventSignal **) data; + _test_event_called++; + parcEventSignal_Stop(*parcEventSignal); +} + +LONGBOW_TEST_CASE(Global, parc_EventSignal_Stop) +{ + _test_event_called = 0; + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + PARCEventSignal *parcEventSignal = parcEventSignal_Create(parcEventScheduler, SIGUSR1, PARCEventType_Signal | PARCEventType_Persist, _test_stop_event, &parcEventSignal); + assertNotNull(parcEventSignal, "parcEventSignal_Create returned a null reference"); + + parcEventSignal_Start(parcEventSignal); + kill(getpid(), SIGUSR1); + + parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking); + assertTrue(_test_event_called == 1, "Event never called."); + + parcEventSignal_Destroy(&parcEventSignal); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_EventSignal); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_EventSocket.c b/libparc/parc/algol/test/test_parc_EventSocket.c new file mode 100644 index 00000000..dbe8892b --- /dev/null +++ b/libparc/parc/algol/test/test_parc_EventSocket.c @@ -0,0 +1,128 @@ +/* + * 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 <pthread.h> + +#include <arpa/inet.h> + +#include <LongBow/unit-test.h> + +#include <parc/algol/parc_SafeMemory.h> +#include <parc/algol/parc_EventSocket.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../parc_EventSocket.c" + +LONGBOW_TEST_RUNNER(parc_EventSocket) +{ + // 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(parc_EventSocket) +{ + parcEventSocket_EnableDebug(); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_EventSocket) +{ + parcEventSocket_DisableDebug(); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parc_EventSocket_Create_Destroy); +} + +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; +} + +static int _test_event_called = 0; + +static void +listener_callback(int fd, struct sockaddr *sa, int socklen, void *user_data) +{ + _test_event_called++; +} + +static int _test_error_event_called = 0; + +static void +listener_error_callback(PARCEventScheduler *base, int error, char *errorString, void *addr_unix) +{ + _test_error_event_called++; +} + +LONGBOW_TEST_CASE(Global, parc_EventSocket_Create_Destroy) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(49009); + inet_pton(AF_INET, "127.0.0.1", &(addr.sin_addr)); + + PARCEventSocket *parcEventSocket = parcEventSocket_Create(parcEventScheduler, + listener_callback, + listener_error_callback, + NULL, NULL, 0); + assertNull(parcEventSocket, "parcEventSocket_Create didn't return an error when expected"); + + parcEventSocket = parcEventSocket_Create(parcEventScheduler, + listener_callback, + listener_error_callback, + NULL, (struct sockaddr *) &addr, sizeof(addr)); + assertNotNull(parcEventSocket, "parcEventSocket_Create returned a null reference"); + + _parc_evconn_callback(NULL, 0, (struct sockaddr *) &addr, sizeof(addr), parcEventSocket); + assertTrue(_test_event_called == 1, "Listener callback wasn't triggered"); + _parc_evconn_error_callback(NULL, parcEventSocket); + assertTrue(_test_error_event_called == 1, "Listener error callback wasn't triggered"); + + parcEventSocket_Destroy(&parcEventSocket); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_EventSocket); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_EventTimer.c b/libparc/parc/algol/test/test_parc_EventTimer.c new file mode 100755 index 00000000..f6b9917e --- /dev/null +++ b/libparc/parc/algol/test/test_parc_EventTimer.c @@ -0,0 +1,143 @@ +/* + * 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 <pthread.h> + +#include <LongBow/unit-test.h> + +#include <parc/algol/parc_SafeMemory.h> +#include <parc/algol/parc_EventTimer.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../parc_EventTimer.c" + +LONGBOW_TEST_RUNNER(parc_EventTimer) +{ + // 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(parc_EventTimer) +{ + parcEventTimer_EnableDebug(); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_EventTimer) +{ + parcEventTimer_DisableDebug(); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parc_EventTimer_Create_Destroy); + LONGBOW_RUN_TEST_CASE(Global, parc_EventTimer_Start); + LONGBOW_RUN_TEST_CASE(Global, parc_EventTimer_Stop); +} + +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; +} + +static int _test_event_called = 0; + +static void +_test_event(int fd, PARCEventType flags, void *data) +{ + _test_event_called++; +} + +LONGBOW_TEST_CASE(Global, parc_EventTimer_Create_Destroy) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + PARCEventTimer *parcEventTimer = parcEventTimer_Create(parcEventScheduler, PARCEventType_None, _test_event, NULL); + assertNotNull(parcEventTimer, "parcEventTimer_Create returned a null reference"); + + parcEventTimer_Destroy(&parcEventTimer); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +LONGBOW_TEST_CASE(Global, parc_EventTimer_Start) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + PARCEventTimer *parcEventTimer = parcEventTimer_Create(parcEventScheduler, PARCEventType_None, _test_event, NULL); + assertNotNull(parcEventTimer, "parcEventTimer_Create returned a null reference"); + + struct timeval timeout = { 1, 0 }; + parcEventTimer_Start(parcEventTimer, &timeout); + parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking); + assertTrue(_test_event_called == 1, "Event never called."); + + parcEventTimer_Destroy(&parcEventTimer); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +static void +_test_stop_event(int fd, PARCEventType flags, void *data) +{ + PARCEventTimer **parcEventTimer = (PARCEventTimer **) data; + _test_event_called++; + parcEventTimer_Stop(*parcEventTimer); +} + +LONGBOW_TEST_CASE(Global, parc_EventTimer_Stop) +{ + PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create(); + assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference"); + + PARCEventTimer *parcEventTimer = parcEventTimer_Create(parcEventScheduler, PARCEventType_None | PARCEventType_Persist, _test_stop_event, &parcEventTimer); + assertNotNull(parcEventTimer, "parcEventTimer_Create returned a null reference"); + + _test_event_called = 0; + struct timeval timeout = { 1, 0 }; + parcEventTimer_Start(parcEventTimer, &timeout); + parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking); + assertTrue(_test_event_called == 1, "Event never called."); + + parcEventTimer_Destroy(&parcEventTimer); + parcEventScheduler_Destroy(&parcEventScheduler); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_EventTimer); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_File.c b/libparc/parc/algol/test/test_parc_File.c new file mode 100644 index 00000000..eccef210 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_File.c @@ -0,0 +1,208 @@ +/* + * 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 <LongBow/unit-test.h> +#include <fcntl.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../parc_SafeMemory.h" +#include "../parc_File.c" + +#define PATH_SEGMENT "A" + +LONGBOW_TEST_RUNNER(parc_File) +{ + // 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(Local); + LONGBOW_RUN_TEST_FIXTURE(AcquireRelease); + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_File) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_File) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(AcquireRelease) +{ + LONGBOW_RUN_TEST_CASE(AcquireRelease, parcFile_AcquireRelease); +} + +LONGBOW_TEST_FIXTURE_SETUP(AcquireRelease) +{ + longBowClipBoard_SetInt(testClipBoard, "initalAllocations", parcMemory_Outstanding()); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(AcquireRelease) +{ + uint64_t initialAllocations = longBowClipBoard_GetAsInt(testClipBoard, "initalAllocations"); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + if (initialAllocations < outstandingAllocations) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(AcquireRelease, parcFile_AcquireRelease) +{ + char *root = "/tmp/test_parc_File"; + + PARCFile *file = parcFile_Create(root); + + PARCFile *reference = parcFile_Acquire(file); + + parcFile_Release(&reference); + + parcFile_AssertValid(file); + + parcFile_Release(&file); +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcFile_CreateChild); + LONGBOW_RUN_TEST_CASE(Global, parcFile_CreateDeleteNewFile); + LONGBOW_RUN_TEST_CASE(Global, parcFile_CreateDelete_Directory); + LONGBOW_RUN_TEST_CASE(Global, parcFile_Exists); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + longBowClipBoard_SetInt(testClipBoard, "initalAllocations", parcMemory_Outstanding()); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint64_t initialAllocations = longBowClipBoard_GetAsInt(testClipBoard, "initalAllocations"); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + if (initialAllocations < outstandingAllocations) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, parcFile_Exists) +{ + char *root = "/tmp"; + + PARCFile *parent = parcFile_Create(root); + + char *child = "foo"; + PARCFile *file = parcFile_CreateChild(parent, child); + + parcFile_CreateNewFile(file); + + bool actual = parcFile_Exists(file); + + assertTrue(actual, "Expected the file to exist."); + + parcFile_Release(&file); + parcFile_Release(&parent); +} + +LONGBOW_TEST_CASE(Global, parcFile_CreateChild) +{ + char *root = "/tmp"; + + PARCFile *parent = parcFile_Create(root); + + char *child = "foo"; + PARCFile *file = parcFile_CreateChild(parent, child); + + char *actual = parcFile_ToString(file); + + assertTrue(strcmp("/tmp/foo", actual) == 0, + "Expected %s, actual %s", "/tmp/foo", actual); + + parcMemory_Deallocate((void **) &actual); + parcFile_Release(&file); + parcFile_Release(&parent); +} + +LONGBOW_TEST_CASE(Global, parcFile_CreateDeleteNewFile) +{ + char *name = "/tmp/test_parc_File"; + + PARCFile *file = parcFile_Create(name); + + parcFile_CreateNewFile(file); + + bool actual = parcFile_Delete(file); + assertTrue(actual, "Expected parcFile_Delete to return true."); + + parcFile_Release(&file); +} + +LONGBOW_TEST_CASE(Global, parcFile_CreateDelete_Directory) +{ + char *name = "/tmp/test_parc_File_directory"; + + PARCFile *directory = parcFile_Create(name); + + parcFile_Mkdir(directory); + + char *fileName = "foo"; + PARCFile *file = parcFile_CreateChild(directory, fileName); + + bool success = parcFile_CreateNewFile(file); + assertTrue(success, "Expected parcFile_CreateNewFile success"); + + bool actual = parcFile_Delete(directory); + assertTrue(actual, "Expected parcFile_Delete to return true."); + + parcFile_Release(&file); + parcFile_Release(&directory); +} + +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(parc_File); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_FileChunker.c b/libparc/parc/algol/test/test_parc_FileChunker.c new file mode 100755 index 00000000..6060cff6 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_FileChunker.c @@ -0,0 +1,431 @@ +/* + * 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 "../parc_FileChunker.c" + +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> +#include <parc/algol/parc_BufferChunker.h> + +LONGBOW_TEST_RUNNER(parc_FileChunker) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_FileChunker) +{ + 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(parc_FileChunker) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_CreateFromFile); + LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ForwardIterator_File); + LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ForwardIterator_FilePartial); + LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ForwardIterator_FileSmall); + LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ReverseIterator_File); + LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ReverseIterator_FilePartial); + LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ReverseIterator_FileSmall); + LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_GetChunkSize); +} + +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; +} + +static void +_createFile(char *fname, PARCBuffer *buffer) +{ + PARCFile *file = parcFile_Create(fname); + if (!parcFile_Exists(file)) { + parcFile_CreateNewFile(file); + } + PARCRandomAccessFile *fhandle = parcRandomAccessFile_Open(file); + parcFile_Release(&file); + + parcRandomAccessFile_Write(fhandle, buffer); + parcRandomAccessFile_Close(fhandle); + parcRandomAccessFile_Release(&fhandle); +} + +static void +_deleteFile(char *fname) +{ + PARCFile *file = parcFile_Create(fname); + parcFile_Delete(file); + parcFile_Release(&file); +} + +LONGBOW_TEST_CASE(Global, parc_Chunker_CreateFromFile) +{ + PARCBuffer *buffer = parcBuffer_Allocate(1024); + + for (size_t i = 0; i < 32; i++) { + for (size_t j = 0; j < 32; j++) { + parcBuffer_PutUint8(buffer, i); + } + } + parcBuffer_Flip(buffer); + + _createFile("/tmp/file_chunker.tmp", buffer); + + PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp"); + + PARCFileChunker *chunker = parcFileChunker_Create(file, 32); // each chunk is 32 bytes + PARCFileChunker *copy = parcFileChunker_Acquire(chunker); + assertNotNull(chunker, "Expected non-NULL Chunker"); + assertNotNull(copy, "Expected non-NULL copy of Chunker"); + parcFileChunker_Release(©); + + parcFile_Release(&file); + parcFileChunker_Release(&chunker); + + _deleteFile("/tmp/file_chunker.tmp"); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parc_Chunker_ForwardIterator_File) +{ + PARCBuffer *buffer = parcBuffer_Allocate(1024); + + for (size_t i = 0; i < 32; i++) { + for (size_t j = 0; j < 32; j++) { + parcBuffer_PutUint8(buffer, i); + } + } + parcBuffer_Flip(buffer); + + _createFile("/tmp/file_chunker.tmp", buffer); + + PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp"); + + PARCFileChunker *chunker = parcFileChunker_Create(file, 32); // each chunk is 32 bytes + assertNotNull(chunker, "Expected non-NULL Chunker"); + + PARCIterator *itr = parcFileChunker_ForwardIterator(chunker); + size_t count = 0; + while (parcIterator_HasNext(itr)) { + PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr); + + uint8_t *contents = parcBuffer_Overlay(payload, 0); + for (size_t i = 0; i < 32; i++) { + assertTrue(contents[i] == count, "Expected %zu at index %zu, got %d", count, i, contents[i]); + } + count++; + + parcBuffer_Release(&payload); + } + assertTrue(count == 32, "Expected to iterate over 32 content objects from the chunker, but for %zu", count); + parcIterator_Release(&itr); + + parcFile_Release(&file); + parcFileChunker_Release(&chunker); + + _deleteFile("/tmp/file_chunker.tmp"); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parc_Chunker_ForwardIterator_FilePartial) +{ + PARCBuffer *buffer = parcBuffer_Allocate(1030); + + for (size_t i = 0; i < 32; i++) { + for (size_t j = 0; j < 32; j++) { + parcBuffer_PutUint8(buffer, i); + } + } + + // Special 0xFF to mark the end... + for (int i = 0; i < 6; i++) { + parcBuffer_PutUint8(buffer, 0xFF); + } + parcBuffer_Flip(buffer); + + _createFile("/tmp/file_chunker.tmp", buffer); + + PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp"); + + PARCFileChunker *chunker = parcFileChunker_Create(file, 32); // each chunk is 32 bytes + assertNotNull(chunker, "Expected non-NULL Chunker"); + + PARCIterator *itr = parcFileChunker_ForwardIterator(chunker); + size_t count = 0; + while (parcIterator_HasNext(itr)) { + PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr); + + uint8_t *contents = parcBuffer_Overlay(payload, 0); + if (count < 32) { + for (size_t i = 0; i < 32; i++) { + assertTrue(contents[i] == count, "Expected %zu at index %zu, got %d", count, i, contents[i]); + } + } else { + for (size_t i = 0; i < 6; i++) { + assertTrue(contents[i] == 0xFF, "Expected %zu at index %zu, got %d", (size_t) 0xFF, i, contents[i]); + } + } + count++; + + parcBuffer_Release(&payload); + } + assertTrue(count == 33, "Expected to iterate over 33 content objects from the chunker, but for %zu", count); + parcIterator_Release(&itr); + + parcFile_Release(&file); + parcFileChunker_Release(&chunker); + + _deleteFile("/tmp/file_chunker.tmp"); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parc_Chunker_ForwardIterator_FileSmall) +{ + PARCBuffer *buffer = parcBuffer_Allocate(16); + + // Special 0xFF to mark the end... + for (int i = 0; i < 16; i++) { + parcBuffer_PutUint8(buffer, 0xFF); + } + parcBuffer_Flip(buffer); + + _createFile("/tmp/file_chunker.tmp", buffer); + + PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp"); + + PARCFileChunker *chunker = parcFileChunker_Create(file, 4096); // each chunk is 1024 bytes + assertNotNull(chunker, "Expected non-NULL Chunker"); + + PARCIterator *itr = parcFileChunker_ForwardIterator(chunker); + size_t count = 0; + while (parcIterator_HasNext(itr)) { + PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr); + + uint8_t *contents = parcBuffer_Overlay(payload, 0); + for (size_t i = 0; i < 16; i++) { + assertTrue(contents[i] == 0xFF, "Expected %zu at index %zu, got %d", (size_t) 0xFF, i, contents[i]); + } + count++; + + parcBuffer_Release(&payload); + } + assertTrue(count == 1, "Expected to iterate over 1 content objects from the chunker, but for %zu", count); + parcIterator_Release(&itr); + + parcFile_Release(&file); + parcFileChunker_Release(&chunker); + + _deleteFile("/tmp/file_chunker.tmp"); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parc_Chunker_ReverseIterator_File) +{ + PARCBuffer *buffer = parcBuffer_Allocate(1024); + + for (size_t i = 0; i < 32; i++) { + for (size_t j = 0; j < 32; j++) { + parcBuffer_PutUint8(buffer, i); + } + } + parcBuffer_Flip(buffer); + + _createFile("/tmp/file_chunker.tmp", buffer); + + PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp"); + + PARCFileChunker *chunker = parcFileChunker_Create(file, 32); // each chunk is 32 bytes + assertNotNull(chunker, "Expected non-NULL Chunker"); + + PARCIterator *itr = parcFileChunker_ReverseIterator(chunker); + size_t count = 0; + while (parcIterator_HasNext(itr)) { + PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr); + + uint8_t *contents = parcBuffer_Overlay(payload, 0); + for (size_t i = 0; i < 32; i++) { + assertTrue(contents[i] == (31 - count), "Expected %zu at index %zu, got %d", count, i, contents[i]); + } + count++; + + parcBuffer_Release(&payload); + } + assertTrue(count == 32, "Expected to iterate over 32 content objects from the chunker, but for %zu", count); + parcIterator_Release(&itr); + + parcFile_Release(&file); + parcFileChunker_Release(&chunker); + + _deleteFile("/tmp/file_chunker.tmp"); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parc_Chunker_ReverseIterator_FilePartial) +{ + PARCBuffer *buffer = parcBuffer_Allocate(1030); + + // Special 0xFF to mark the start... + for (int i = 0; i < 6; i++) { + parcBuffer_PutUint8(buffer, 0xFF); + } + + for (size_t i = 0; i < 32; i++) { + for (size_t j = 0; j < 32; j++) { + parcBuffer_PutUint8(buffer, i); + } + } + parcBuffer_Flip(buffer); + + _createFile("/tmp/file_chunker.tmp", buffer); + + PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp"); + + PARCFileChunker *chunker = parcFileChunker_Create(file, 32); // each chunk is 32 bytes + assertNotNull(chunker, "Expected non-NULL Chunker"); + + PARCIterator *itr = parcFileChunker_ReverseIterator(chunker); + size_t count = 0; + while (parcIterator_HasNext(itr)) { + PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr); + + uint8_t *contents = parcBuffer_Overlay(payload, 0); + if (count < 32) { + for (size_t i = 0; i < 32; i++) { + assertTrue(contents[i] == (31 - count), "Expected %zu at index %zu, got %d", (31 - count), i, contents[i]); + } + } else { + for (size_t i = 0; i < 6; i++) { + assertTrue(contents[i] == 0xFF, "Expected %zu at index %zu, got %d", (size_t) 0xFF, i, contents[i]); + } + } + count++; + + parcBuffer_Release(&payload); + } + assertTrue(count == 33, "Expected to iterate over 33 content objects from the chunker, but for %zu", count); + parcIterator_Release(&itr); + + parcFile_Release(&file); + parcFileChunker_Release(&chunker); + + _deleteFile("/tmp/file_chunker.tmp"); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parc_Chunker_ReverseIterator_FileSmall) +{ + PARCBuffer *buffer = parcBuffer_Allocate(1030); + + // Special 0xFF to mark the start... + for (int i = 0; i < 6; i++) { + parcBuffer_PutUint8(buffer, 0xFF); + } + parcBuffer_Flip(buffer); + + _createFile("/tmp/file_chunker.tmp", buffer); + + PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp"); + + PARCFileChunker *chunker = parcFileChunker_Create(file, 32); // each chunk is 32 bytes + assertNotNull(chunker, "Expected non-NULL Chunker"); + + PARCIterator *itr = parcFileChunker_ReverseIterator(chunker); + size_t count = 0; + while (parcIterator_HasNext(itr)) { + PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr); + + uint8_t *contents = parcBuffer_Overlay(payload, 0); + for (size_t i = 0; i < 6; i++) { + assertTrue(contents[i] == 0xFF, "Expected %zu at index %zu, got %d", (size_t) 0xFF, i, contents[i]); + } + count++; + + parcBuffer_Release(&payload); + } + assertTrue(count == 1, "Expected to iterate over 1 content objects from the chunker, but for %zu", count); + parcIterator_Release(&itr); + + parcFile_Release(&file); + parcFileChunker_Release(&chunker); + + _deleteFile("/tmp/file_chunker.tmp"); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parc_Chunker_GetChunkSize) +{ + size_t expectedChunkSize = 32; + PARCBuffer *buffer = parcBuffer_Allocate(1030); + + // Special 0xFF to mark the start... + for (int i = 0; i < 6; i++) { + parcBuffer_PutUint8(buffer, 0xFF); + } + parcBuffer_Flip(buffer); + + _createFile("/tmp/file_chunker.tmp", buffer); + + PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp"); + PARCFileChunker *chunker = parcFileChunker_Create(file, expectedChunkSize); // each chunk is 32 bytes + + size_t actualChunkSize = parcBufferChunker_GetChunkSize(chunker); + + assertTrue(actualChunkSize == expectedChunkSize, "Expected chunk size of %zu, got %zu", expectedChunkSize, actualChunkSize); + + parcFile_Release(&file); + parcFileChunker_Release(&chunker); + + _deleteFile("/tmp/file_chunker.tmp"); + + parcBuffer_Release(&buffer); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_FileChunker); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_FileInputStream.c b/libparc/parc/algol/test/test_parc_FileInputStream.c new file mode 100755 index 00000000..49032050 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_FileInputStream.c @@ -0,0 +1,107 @@ +/* + * 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. + */ + +/** + * @header <#Headline Name#> + * @abstract <#Abstract#> + * @discussion + * <#Discussion#> + * + */ +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../parc_FileInputStream.c" + +#include <LongBow/unit-test.h> +#include <LongBow/debugging.h> + +#include <parc/algol/parc_File.h> +#include <parc/algol/parc_SafeMemory.h> + +LONGBOW_TEST_RUNNER(test_parc_FileInputStream) +{ + // 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_parc_FileInputStream) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_FileInputStream) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcFileInputStream_Open); + LONGBOW_RUN_TEST_CASE(Global, parcFileInputStream_ReadFile); +} + +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, parcFileInputStream_Open) +{ + PARCFile *file = parcFile_Create("test_parc_FileInputStream"); + PARCFileInputStream *stream = parcFileInputStream_Open(file); + + parcFileInputStream_Release(&stream); + parcFile_Release(&file); +} + +LONGBOW_TEST_CASE(Global, parcFileInputStream_ReadFile) +{ + PARCFile *file = parcFile_Create("test_parc_FileInputStream"); + PARCFileInputStream *stream = parcFileInputStream_Open(file); + + PARCBuffer *actual = parcFileInputStream_ReadFile(stream); + assertNotNull(actual, "Expected non-null result from parcFileInputStream_ReadFile"); + + parcBuffer_Flip(actual); + + assertTrue(parcBuffer_HasRemaining(actual), "Expected the buffer to contain data."); + + parcBuffer_Release(&actual); + parcFileInputStream_Release(&stream); + parcFile_Release(&file); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_FileInputStream); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_FileOutputStream.c b/libparc/parc/algol/test/test_parc_FileOutputStream.c new file mode 100755 index 00000000..aa4236ae --- /dev/null +++ b/libparc/parc/algol/test/test_parc_FileOutputStream.c @@ -0,0 +1,167 @@ +/* + * 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 <LongBow/unit-test.h> +#include <fcntl.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../parc_SafeMemory.h" +#include "../parc_FileOutputStream.c" + +#define PATH_SEGMENT "A" + +LONGBOW_TEST_RUNNER(parc_FileOutputStream) +{ + // 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(Local); + LONGBOW_RUN_TEST_FIXTURE(AcquireRelease); + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_FileOutputStream) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_FileOutputStream) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(AcquireRelease) +{ + LONGBOW_RUN_TEST_CASE(AcquireRelease, parcFileOutputStream_Create); + LONGBOW_RUN_TEST_CASE(AcquireRelease, parcFileOutputStream_Release); + LONGBOW_RUN_TEST_CASE(AcquireRelease, parcFileOutputStream_AcquireRelease); +} + +LONGBOW_TEST_FIXTURE_SETUP(AcquireRelease) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(AcquireRelease) +{ + unlink("/tmp/test_parc_FileOutputStream"); + 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(AcquireRelease, parcFileOutputStream_Create) +{ + PARCFileOutputStream *stream = parcFileOutputStream_Create(open("/tmp/test_parc_FileOutputStream", O_CREAT | O_WRONLY | O_TRUNC, 0600)); + assertNotNull(stream, "Expected a non-null pointer"); + + parcFileOutputStream_Release(&stream); + assertNull(stream, "Expected parcFileOutputStream_Release to null the pointer"); + unlink("/tmp/test_parc_FileOutputStream"); +} + +LONGBOW_TEST_CASE(AcquireRelease, parcFileOutputStream_Release) +{ + PARCFileOutputStream *stream = parcFileOutputStream_Create(open("/tmp/test_parc_FileOutputStream", O_CREAT | O_WRONLY | O_TRUNC, 0600)); + assertNotNull(stream, "Expected a non-null pointer"); + + parcFileOutputStream_Release(&stream); + assertNull(stream, "Expected parcFileOutputStream_Release to null the pointer"); + unlink("/tmp/test_parc_FileOutputStream"); +} + +LONGBOW_TEST_CASE(AcquireRelease, parcFileOutputStream_AcquireRelease) +{ + PARCFileOutputStream *stream = parcFileOutputStream_Create(open("/tmp/test_parc_FileOutputStream", O_CREAT | O_WRONLY | O_TRUNC, 0600)); + assertNotNull(stream, "Expected a non-null pointer"); + + PARCFileOutputStream *reference = parcFileOutputStream_Acquire(stream); + assertTrue(stream == reference, "Expected the reference to be equal to the original."); + + parcFileOutputStream_Release(&stream); + assertNull(stream, "Expected parcFileOutputStream_Release to null the pointer"); + + parcFileOutputStream_Release(&reference); + unlink("/tmp/test_parc_FileOutputStream"); +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcFileOutputStream_Write); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + unlink("/tmp/test_parc_FileOutputStream"); + + 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, parcFileOutputStream_Write) +{ + PARCFileOutputStream *stream = + parcFileOutputStream_Create(open("/tmp/test_parc_FileOutputStream", O_CREAT | O_WRONLY | O_TRUNC, 0600)); + + PARCBuffer *buffer = parcBuffer_Allocate(16 * 1024 * 1024); + + parcFileOutputStream_Write(stream, buffer); + + assertFalse(parcBuffer_HasRemaining(buffer), "Expected the buffer to be emtpy"); + + parcBuffer_Release(&buffer); + + parcFileOutputStream_Release(&stream); + unlink("/tmp/test_parc_FileOutputStream"); +} + +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(parc_FileOutputStream); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_Hash.c b/libparc/parc/algol/test/test_parc_Hash.c new file mode 100755 index 00000000..cc92a867 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_Hash.c @@ -0,0 +1,253 @@ +/* + * 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 "../parc_Hash.c" + +#include <LongBow/testing.h> +#include <stdio.h> + +#include <parc/algol/parc_SafeMemory.h> + +LONGBOW_TEST_RUNNER(parc_Hash) +{ + // 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(parc_Hash) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_Hash) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcHash32Bit_Create); + LONGBOW_RUN_TEST_CASE(Global, parcHash32Bit_Acquire); + LONGBOW_RUN_TEST_CASE(Global, parcHash32Bit_Release); + LONGBOW_RUN_TEST_CASE(Global, parcHash32Bit_Update); + LONGBOW_RUN_TEST_CASE(Global, parcHash32Bit_UpdateUint32); + LONGBOW_RUN_TEST_CASE(Global, parcHash32Bit_Hash); + + LONGBOW_RUN_TEST_CASE(Global, parc_Hash32_Data); + LONGBOW_RUN_TEST_CASE(Global, parc_Hash32_Int32); + LONGBOW_RUN_TEST_CASE(Global, parc_Hash32_Int64); + LONGBOW_RUN_TEST_CASE(Global, parc_Hash64_Data); + LONGBOW_RUN_TEST_CASE(Global, parc_Hash64_Int32); + LONGBOW_RUN_TEST_CASE(Global, parc_Hash64_Int64); +} + +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, parcHash32Bit_Create) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Global, parcHash32Bit_Acquire) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Global, parcHash32Bit_Release) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Global, parcHash32Bit_Update) +{ + PARCHash32Bits *hash = parcHash32Bits_Create(); + parcHash32Bits_Update(hash, "123", 3); + uint32_t value = parcHash32Bits_Hash(hash); + assertTrue(value != 0, "Expected a non-zero (non-initial) value"); + + parcHash32Bits_Release(&hash); +} + +LONGBOW_TEST_CASE(Global, parcHash32Bit_UpdateUint32) +{ + PARCHash32Bits *hash = parcHash32Bits_Create(); + parcHash32Bits_UpdateUint32(hash, 123); + uint32_t value = parcHash32Bits_Hash(hash); + assertTrue(value != 0, "Expected a non-zero (non-initial) value"); + + parcHash32Bits_Release(&hash); +} + +LONGBOW_TEST_CASE(Global, parcHash32Bit_Hash) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Global, parc_Hash32_Data) +{ + char *data1 = "Hello World"; + char *data2 = "Hello World1"; + char *data3 = "Hello World2"; + + char data4[20]; + strncpy(data4, data1, sizeof(data4)); + + uint32_t hash1 = parcHash32_Data(data1, strlen(data1)); + uint32_t hash2 = parcHash32_Data(data2, strlen(data2)); + uint32_t hash3 = parcHash32_Data(data3, strlen(data3)); + uint32_t hash4 = parcHash32_Data(data4, strlen(data4)); + + assertTrue(hash1 != 0, "Hash is 0, unlikely"); + assertTrue(hash2 != 0, "Hash is 0, unlikely"); + assertTrue(hash3 != 0, "Hash is 0, unlikely"); + assertTrue(hash4 != 0, "Hash is 0, unlikely"); + assertTrue(hash1 != hash2, "Hash collision, unlikely"); + assertTrue(hash3 != hash2, "Hash collision, unlikely"); + assertTrue(hash3 != hash1, "Hash collision, unlikely"); + assertTrue(hash1 == hash4, "Hash different for same content"); +} + +LONGBOW_TEST_CASE(Global, parc_Hash32_Int32) +{ + uint32_t data1 = 12345; + uint32_t data2 = 12346; + uint32_t data3 = 12345; + + uint32_t hash1 = parcHash32_Int32(data1); + uint32_t hash2 = parcHash32_Int32(data2); + uint32_t hash3 = parcHash32_Int32(data3); + + assertTrue(hash1 != 0, "Hash is 0, unlikely"); + assertTrue(hash2 != 0, "Hash is 0, unlikely"); + assertTrue(hash3 != 0, "Hash is 0, unlikely"); + assertTrue(hash1 != hash2, "Hash collision, unlikely"); + assertTrue(hash1 == hash3, "Hash different for same content"); +} + +LONGBOW_TEST_CASE(Global, parc_Hash32_Int64) +{ + uint64_t data1 = 10010010012345; + uint64_t data2 = 10010010012346; + uint64_t data3 = 10010010012345; + + uint32_t hash1 = parcHash32_Int64(data1); + uint32_t hash2 = parcHash32_Int64(data2); + uint32_t hash3 = parcHash32_Int64(data3); + + assertTrue(hash1 != 0, "Hash is 0, unlikely"); + assertTrue(hash2 != 0, "Hash is 0, unlikely"); + assertTrue(hash3 != 0, "Hash is 0, unlikely"); + assertTrue(hash1 != hash2, "Hash collision, unlikely"); + assertTrue(hash1 == hash3, "Hash different for same content"); +} + +LONGBOW_TEST_CASE(Global, parc_Hash64_Data) +{ + char *data1 = "Hello World"; + char *data2 = "Hello World1"; + char *data3 = "Hello World2"; + + char data4[20]; + strncpy(data4, data1, sizeof(data4)); + + uint64_t hash1 = parcHash64_Data(data1, strlen(data1)); + uint64_t hash2 = parcHash64_Data(data2, strlen(data2)); + uint64_t hash3 = parcHash64_Data(data3, strlen(data3)); + uint64_t hash4 = parcHash64_Data(data4, strlen(data4)); + + assertTrue(hash1 != 0, "Hash is 0, unlikely"); + assertTrue(hash2 != 0, "Hash is 0, unlikely"); + assertTrue(hash3 != 0, "Hash is 0, unlikely"); + assertTrue(hash4 != 0, "Hash is 0, unlikely"); + assertTrue(hash1 != hash2, "Hash collision, unlikely"); + assertTrue(hash3 != hash2, "Hash collision, unlikely"); + assertTrue(hash3 != hash1, "Hash collision, unlikely"); + assertTrue(hash1 == hash4, "Hash different for same content"); +} + +LONGBOW_TEST_CASE(Global, parc_Hash64_Int32) +{ + uint32_t data1 = 12345; + uint32_t data2 = 12346; + uint32_t data3 = 12345; + + uint64_t hash1 = parcHash64_Int32(data1); + uint64_t hash2 = parcHash64_Int32(data2); + uint64_t hash3 = parcHash64_Int32(data3); + + assertTrue(hash1 != 0, "Hash is 0, unlikely"); + assertTrue(hash2 != 0, "Hash is 0, unlikely"); + assertTrue(hash3 != 0, "Hash is 0, unlikely"); + assertTrue(hash1 != hash2, "Hash collision, unlikely"); + assertTrue(hash1 == hash3, "Hash different for same content"); +} + +LONGBOW_TEST_CASE(Global, parc_Hash64_Int64) +{ + uint64_t data1 = 10010010012345; + uint64_t data2 = 10010010012346; + uint64_t data3 = 10010010012345; + + uint64_t hash1 = parcHash64_Int64(data1); + uint64_t hash2 = parcHash64_Int64(data2); + uint64_t hash3 = parcHash64_Int64(data3); + + assertTrue(hash1 != 0, "Hash is 0, unlikely"); + assertTrue(hash2 != 0, "Hash is 0, unlikely"); + assertTrue(hash3 != 0, "Hash is 0, unlikely"); + assertTrue(hash1 != hash2, "Hash collision, unlikely"); + assertTrue(hash1 == hash3, "Hash different for same content"); +} + +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[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Hash); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_HashCode.c b/libparc/parc/algol/test/test_parc_HashCode.c new file mode 100755 index 00000000..a5b21137 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_HashCode.c @@ -0,0 +1,109 @@ +/* + * 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 "../parc_HashCode.c" + +#include <LongBow/testing.h> +#include <LongBow/debugging.h> + +LONGBOW_TEST_RUNNER(test_parc_HashCode) +{ + // 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_parc_HashCode) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_HashCode) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcHashCode_HashImpl); + LONGBOW_RUN_TEST_CASE(Global, parcHashCode_HashHashCode); + LONGBOW_RUN_TEST_CASE(Global, parcHashCode_Hash); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, parcHashCode_HashImpl) +{ + PARCHashCode lastValue = 0; + uint8_t *memory = (uint8_t *) "1234"; + size_t length = 4; + + PARCHashCode expected = 3316911679945239212ULL; + PARCHashCode actual = parcHashCode_HashImpl(memory, length, lastValue); + + assertTrue(expected == actual, "Expected %" PRIPARCHashCode " actual %" PRIPARCHashCode, expected, actual); +} + +LONGBOW_TEST_CASE(Global, parcHashCode_HashHashCode) +{ + PARCHashCode lastValue = 0; + uint8_t *memory = (uint8_t *) "1234"; + size_t length = 4; + + PARCHashCode lastHash = parcHashCode_HashImpl(memory, length, lastValue); + + PARCHashCode hashedHash = parcHashCode_HashHashCode(lastHash, 123456); + + assertTrue(lastHash != 0, "Expected a non zero hash value for lastHash"); + assertTrue(hashedHash != 0, "Expected a non zero hash value for hashedHash"); + assertTrue(lastHash != hashedHash, "Expected different hash values for hashedHash and lastHash"); +} + +LONGBOW_TEST_CASE(Global, parcHashCode_Hash) +{ + char *testString1 = "this is some test data"; + char *testString2 = "this is different test data"; + + PARCHashCode hash1 = parcHashCode_Hash((uint8_t *) testString1, strlen(testString1)); + PARCHashCode hash2 = parcHashCode_Hash((uint8_t *) testString2, strlen(testString2)); + + assertTrue(hash1 != 0, "Expected a non zero hash value for testString1"); + assertTrue(hash2 != 0, "Expected a non zero hash value for testString2"); + assertTrue(hash1 != hash2, "Expected different hash values for testString1 and testString2"); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_HashCode); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_HashCodeTable.c b/libparc/parc/algol/test/test_parc_HashCodeTable.c new file mode 100755 index 00000000..c2adf9d2 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_HashCodeTable.c @@ -0,0 +1,423 @@ +/* + * 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 <time.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/time.h> + +#include <LongBow/unit-test.h> + +#include "../parc_HashCodeTable.c" + +#include <parc/algol/parc_SafeMemory.h> + +// ============================== +// The objects to put in the hash table. We have a separate key class and data class + +typedef struct test_key_class { + unsigned key_value; + unsigned hash_value; +} TestKeyClass; + +typedef struct test_data_class { + unsigned data_value; +} TestDataClass; + +static bool +TestKeyClass_Equals(const void *a, const void *b) +{ + return ((TestKeyClass *) a)->key_value == ((TestKeyClass *) b)->key_value; +} + +static HashCodeType +TestKeyClass_Hash(const void *a) +{ + return ((TestKeyClass *) a)->hash_value; +} + +static void +TestKeyClassDestroy(void **aPtr) +{ + parcMemory_Deallocate((void **) aPtr); + aPtr = NULL; +} + +static void +TestDataClassDestroy(void **aPtr) +{ + parcMemory_Deallocate((void **) aPtr); + aPtr = NULL; +} + +typedef struct truth_table_entry { + unsigned key_value; + unsigned hash_code; + unsigned data_value; +} TruthTableEntry; + +// ============================== + + +LONGBOW_TEST_RUNNER(parc_HashCodeTable) +{ + // 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(parc_HashCodeTable) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_HashCodeTable) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcHashCodeTable_Add_Get); + LONGBOW_RUN_TEST_CASE(Global, parcHashCodeTable_Create); + LONGBOW_RUN_TEST_CASE(Global, parcHashCodeTable_Create_Size); + LONGBOW_RUN_TEST_CASE(Global, parcHashCodeTable_Del); + + LONGBOW_RUN_TEST_CASE(Global, parcHashCodeTable_Add_DuplicateHashes); + LONGBOW_RUN_TEST_CASE(Global, parcHashCodeTable_Add_DuplicateValues); + + LONGBOW_RUN_TEST_CASE(Global, parcHashCodeTable_BigTable); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + 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(Global, parcHashCodeTable_Add_Get) +{ + const int testsize = 4096; + PARCHashCodeTable *table = parcHashCodeTable_Create(TestKeyClass_Equals, TestKeyClass_Hash, TestKeyClassDestroy, TestDataClassDestroy); + TruthTableEntry *truthtable = parcMemory_Allocate(sizeof(TruthTableEntry) * testsize); + assertNotNull(truthtable, "parcMemory_Allocate(%zu) returned NULL", sizeof(TruthTableEntry) * testsize); + int i; + int fd = open("/dev/urandom", O_RDONLY); + + if (fd == -1) { + assertFalse(fd == -1, "Error opening random number generator: %s", strerror(errno)); + } + + ssize_t nread = read(fd, truthtable, sizeof(TruthTableEntry) * testsize); + assertTrue(nread > 0, "Error using read"); + close(fd); + + for (i = 0; i < testsize; i++) { + TestKeyClass *key = parcMemory_AllocateAndClear(sizeof(TestKeyClass)); + assertNotNull(key, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestKeyClass)); + TestDataClass *data = parcMemory_AllocateAndClear(sizeof(TestDataClass)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataClass)); + + key->key_value = truthtable[i].key_value; + key->hash_value = truthtable[i].hash_code; + data->data_value = truthtable[i].data_value; + + bool success = parcHashCodeTable_Add(table, key, data); + assertTrue(success, "Failed inserting value"); + } + + // now retrieve them + for (i = 0; i < testsize; i++) { + TestKeyClass lookupkey; + lookupkey.key_value = truthtable[i].key_value; + lookupkey.hash_value = truthtable[i].hash_code; + + TestDataClass *data = parcHashCodeTable_Get(table, &lookupkey); + assertTrue(data->data_value == truthtable[i].data_value, "Data value incorrect"); + } + + parcHashCodeTable_Destroy(&table); + parcMemory_Deallocate((void **) &truthtable); +} + +LONGBOW_TEST_CASE(Global, parcHashCodeTable_Create) +{ + PARCHashCodeTable *table = parcHashCodeTable_Create(TestKeyClass_Equals, TestKeyClass_Hash, TestKeyClassDestroy, TestDataClassDestroy); + + assertNotNull(table, "table came back as null"); + assertTrue(table->hashtable.tableSize == 0, "Hash table initialized to wrong size"); + assertTrue(table->hashtable.tableLimit == MIN_SIZE, "Initial table limit size is wrong"); + assertTrue(table->keyEqualsFunc == TestKeyClass_Equals, "KeyEqualsFunc wrong"); + assertTrue(table->keyHashCodeFunc == TestKeyClass_Hash, "KeyHashFunc wrong"); + assertTrue(table->keyDestroyer == TestKeyClassDestroy, "KeyDestroyer wrong"); + assertTrue(table->dataDestroyer == TestDataClassDestroy, "DataDestroyer wrong"); + + parcHashCodeTable_Destroy(&table); +} + +LONGBOW_TEST_CASE(Global, parcHashCodeTable_Create_Size) +{ + PARCHashCodeTable *table = parcHashCodeTable_Create_Size(TestKeyClass_Equals, TestKeyClass_Hash, TestKeyClassDestroy, TestDataClassDestroy, 16); + + assertNotNull(table, "table came back as null"); + assertTrue(table->hashtable.tableLimit == 16, "Initial table limit size is wrong"); + parcHashCodeTable_Destroy(&table); +} + +LONGBOW_TEST_CASE(Global, parcHashCodeTable_Del) +{ + const int testsize = 6; + PARCHashCodeTable *table = parcHashCodeTable_Create(TestKeyClass_Equals, TestKeyClass_Hash, TestKeyClassDestroy, TestDataClassDestroy); + TruthTableEntry *truthtable = parcMemory_Allocate(sizeof(TruthTableEntry) * testsize); + assertNotNull(truthtable, "parcMemory_Allocate(%zu) returned NULL", sizeof(TruthTableEntry) * testsize); + int i; + int fd = open("/dev/urandom", O_RDONLY); + + if (fd == -1) { + assertFalse(fd == -1, "Error opening random number generator: %s", strerror(errno)); + } + + ssize_t nread = read(fd, truthtable, sizeof(TruthTableEntry) * testsize); + assertTrue(nread > 0, "Error using read"); + close(fd); + + for (i = 0; i < testsize; i++) { + TestKeyClass *key = parcMemory_AllocateAndClear(sizeof(TestKeyClass)); + assertNotNull(key, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestKeyClass)); + TestDataClass *data = parcMemory_AllocateAndClear(sizeof(TestDataClass)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataClass)); + + key->key_value = truthtable[i].key_value; + key->hash_value = truthtable[i].hash_code; + data->data_value = truthtable[i].data_value; + + bool success = parcHashCodeTable_Add(table, key, data); + assertTrue(success, "Failed inserting value"); + } + + // delete the last one + { + TestKeyClass lookupkey; + + lookupkey.key_value = truthtable[testsize - 1].key_value; + lookupkey.hash_value = truthtable[testsize - 1].hash_code; + + parcHashCodeTable_Del(table, &lookupkey); + assertTrue(table->hashtable.tableSize == testsize - 1, "tableSize wrong"); + } + + for (i = 0; i < testsize - 1; i++) { + TestKeyClass lookupkey; + lookupkey.key_value = truthtable[i].key_value; + lookupkey.hash_value = truthtable[i].hash_code; + + TestDataClass *data = parcHashCodeTable_Get(table, &lookupkey); + assertTrue(data->data_value == truthtable[i].data_value, "Data value incorrect"); + } + + for (i = testsize - 1; i < testsize; i++) { + TestKeyClass lookupkey; + lookupkey.key_value = truthtable[i].key_value; + lookupkey.hash_value = truthtable[i].hash_code; + + TestDataClass *data = parcHashCodeTable_Get(table, &lookupkey); + assertNull(data, "Should not have returned deleted value"); + } + parcHashCodeTable_Destroy(&table); + parcMemory_Deallocate((void **) &truthtable); +} + +LONGBOW_TEST_CASE(Global, parcHashCodeTable_Add_DuplicateHashes) +{ + PARCHashCodeTable *table = parcHashCodeTable_Create(TestKeyClass_Equals, TestKeyClass_Hash, TestKeyClassDestroy, TestDataClassDestroy); + + TestKeyClass *key1 = parcMemory_AllocateAndClear(sizeof(TestKeyClass)); + assertNotNull(key1, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestKeyClass)); + TestKeyClass *key2 = parcMemory_AllocateAndClear(sizeof(TestKeyClass)); + assertNotNull(key2, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestKeyClass)); + TestDataClass *data1 = parcMemory_AllocateAndClear(sizeof(TestDataClass)); + assertNotNull(data1, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataClass)); + TestDataClass *data2 = parcMemory_AllocateAndClear(sizeof(TestDataClass)); + assertNotNull(data2, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataClass)); + TestDataClass *test; + bool success; + + *key1 = (TestKeyClass) { .key_value = 1, .hash_value = 2 }; + *key2 = (TestKeyClass) { .key_value = 3, .hash_value = 2 }; + data1->data_value = 11; + data2->data_value = 22; + + success = parcHashCodeTable_Add(table, key1, data1); + assertTrue(success, "Failed to add value"); + + success = parcHashCodeTable_Add(table, key2, data2); + assertTrue(success, "Failed to add value"); + + // value 3 should be in position 3 + test = parcHashCodeTable_Get(table, key1); + assertNotNull(test, "returned null on get"); + assertTrue(test->data_value == 11, "Got wrong value back for key1"); + + test = parcHashCodeTable_Get(table, key2); + assertNotNull(test, "returned null on get"); + assertTrue(test->data_value == 22, "Got wrong value back for key1"); + + parcHashCodeTable_Destroy(&table); +} + +LONGBOW_TEST_CASE(Global, parcHashCodeTable_Add_DuplicateValues) +{ + PARCHashCodeTable *table = parcHashCodeTable_Create(TestKeyClass_Equals, TestKeyClass_Hash, TestKeyClassDestroy, TestDataClassDestroy); + + TestKeyClass *key1 = parcMemory_AllocateAndClear(sizeof(TestKeyClass)); + assertNotNull(key1, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestKeyClass)); + TestKeyClass *key2 = parcMemory_AllocateAndClear(sizeof(TestKeyClass)); + assertNotNull(key2, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestKeyClass)); + TestDataClass *data1 = parcMemory_AllocateAndClear(sizeof(TestDataClass)); + assertNotNull(data1, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataClass)); + TestDataClass *data2 = parcMemory_AllocateAndClear(sizeof(TestDataClass)); + assertNotNull(data2, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataClass)); + TestDataClass *test; + bool success; + + *key1 = (TestKeyClass) { .key_value = 1, .hash_value = 2 }; + *key2 = (TestKeyClass) { .key_value = 1, .hash_value = 2 }; + data1->data_value = 11; + data2->data_value = 22; + + success = parcHashCodeTable_Add(table, key1, data1); + assertTrue(success, "Failed to add value"); + + success = parcHashCodeTable_Add(table, key2, data2); + assertFalse(success, "Second add should have failed on duplicate key"); + + // value 3 should be in position 3 + test = parcHashCodeTable_Get(table, key1); + assertNotNull(test, "returned null on get"); + assertTrue(test->data_value == 11, "Got wrong value back for key1"); + + parcHashCodeTable_Destroy(&table); + parcMemory_Deallocate((void **) &key2); + parcMemory_Deallocate((void **) &data2); +} + +LONGBOW_TEST_CASE(Global, parcHashCodeTable_BigTable) +{ + PARCHashCodeTable *table = parcHashCodeTable_Create(TestKeyClass_Equals, TestKeyClass_Hash, TestKeyClassDestroy, TestDataClassDestroy); + + struct timeval t0, t1; + + gettimeofday(&t0, NULL); + + int loops = 1000; + for (int i = 0; i < loops; i++) { + TestKeyClass *key = parcMemory_AllocateAndClear(sizeof(TestKeyClass)); + assertNotNull(key, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestKeyClass)); + TestDataClass *data = parcMemory_AllocateAndClear(sizeof(TestDataClass)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataClass)); + + *key = (TestKeyClass) { .key_value = i, .hash_value = i }; + data->data_value = i; + + bool success = parcHashCodeTable_Add(table, key, data); + assertTrue(success, "Failed to add value"); + } + gettimeofday(&t1, NULL); + + timersub(&t1, &t0, &t1); + double sec = t1.tv_sec + t1.tv_usec * 1E-6; + printf("expand count %u, sec = %.3f, sec/add = %.9f\n", table->expandCount, sec, sec / loops); + + gettimeofday(&t0, NULL); + parcHashCodeTable_Destroy(&table); + gettimeofday(&t1, NULL); + + timersub(&t1, &t0, &t1); + sec = t1.tv_sec + t1.tv_usec * 1E-6; + printf("destroy sec = %.3f, sec/add = %.9f\n", sec, sec / loops); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, _findIndex); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + 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, _findIndex) +{ + PARCHashCodeTable *table = parcHashCodeTable_Create(TestKeyClass_Equals, TestKeyClass_Hash, TestKeyClassDestroy, TestDataClassDestroy); + + // stick a data element in the middle of the table + TestKeyClass *key = parcMemory_AllocateAndClear(sizeof(TestKeyClass)); + assertNotNull(key, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestKeyClass)); + TestDataClass *data = parcMemory_AllocateAndClear(sizeof(TestDataClass)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataClass)); + + key->key_value = 1; + key->hash_value = 37; + data->data_value = 7; + + table->hashtable.entries[37].key = key; + table->hashtable.entries[37].hashcode = key->hash_value; + table->hashtable.entries[37].data = data; + + size_t index; + bool success = _findIndex(table, key, &index); + assertTrue(success, "FindIndex did not find known value"); + assertTrue(index == 37, "FindIndex returned wrong value"); + + + parcHashCodeTable_Destroy(&table); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_HashCodeTable); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_HashMap.c b/libparc/parc/algol/test/test_parc_HashMap.c new file mode 100644 index 00000000..1b071f44 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_HashMap.c @@ -0,0 +1,915 @@ +/* + * 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 "../parc_HashMap.c" + +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> +#include <parc/algol/parc_StdlibMemory.h> + +#include <parc/testing/parc_ObjectTesting.h> +#include <parc/testing/parc_MemoryTesting.h> + +LONGBOW_TEST_RUNNER(parc_HashMap) +{ + // 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(Static); + LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease); + LONGBOW_RUN_TEST_FIXTURE(ObjectContract); + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_HashMap) +{ + 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(parc_HashMap) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(CreateAcquireRelease) +{ + LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease); + LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateCapacity0); + LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateCapacityNominal); +} + +LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease) +{ + if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) { + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease) +{ + PARCHashMap *instance = parcHashMap_Create(); + assertNotNull(instance, "Expeced non-null result from parcHashMap_Create();"); + parcObjectTesting_AssertAcquireReleaseContract(parcHashMap_Acquire, instance); + + parcHashMap_Release(&instance); + assertNull(instance, "Expeced null result from parcHashMap_Release();"); +} + +LONGBOW_TEST_CASE(CreateAcquireRelease, CreateCapacity0) +{ + const size_t CAPACITY = 0; + PARCHashMap *instance = parcHashMap_CreateCapacity(CAPACITY); + assertNotNull(instance, "Expeced non-null result from parcHashMap_Create();"); + parcObjectTesting_AssertAcquireReleaseContract(parcHashMap_Acquire, instance); + + parcHashMap_Release(&instance); +} + +LONGBOW_TEST_CASE(CreateAcquireRelease, CreateCapacityNominal) +{ + const size_t CAPACITY = 10000; + PARCHashMap *instance = parcHashMap_CreateCapacity(CAPACITY); + assertNotNull(instance, "Expeced non-null result from parcHashMap_Create();"); + parcObjectTesting_AssertAcquireReleaseContract(parcHashMap_Acquire, instance); + assertTrue(instance->capacity == CAPACITY, "Expect capacity to be %zu", CAPACITY); + assertTrue(instance->size == 0, "Expect size to be 0"); + + //Make sure all the buckets exist + for (size_t i = 0; i < CAPACITY; ++i) { + assertNull(instance->buckets[i], "Expect the hashmap to be clear"); + } + + parcHashMap_Release(&instance); + assertNull(instance, "Expeced null result from parcHashMap_Release();"); +} + +LONGBOW_TEST_FIXTURE(ObjectContract) +{ + LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_Copy); + LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_Display); + LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_Equals); + LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_HashCode_Empty); + LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_HashCode_NonEmpty); + LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_IsValid); + LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_AssertValid); + LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_ToJSON); + LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_ToString); +} + +LONGBOW_TEST_FIXTURE_SETUP(ObjectContract) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(ObjectContract) +{ + if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) { + parcSafeMemory_ReportAllocation(1); + + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(ObjectContract, parcHashMap_Copy) +{ + PARCHashMap *instance = parcHashMap_Create(); + PARCHashMap *copy = parcHashMap_Copy(instance); + + assertTrue(parcHashMap_Equals(instance, copy), "Expected the copy to be equal to the original"); + + parcHashMap_Release(&instance); + parcHashMap_Release(©); +} + +LONGBOW_TEST_CASE(ObjectContract, parcHashMap_Display) +{ + PARCHashMap *x = parcHashMap_Create(); + PARCBuffer *key = parcBuffer_WrapCString("key1"); + PARCBuffer *value = parcBuffer_WrapCString("value1"); + parcHashMap_Put(x, key, value); + parcHashMap_Display(x, 0); + + parcBuffer_Release(&key); + parcBuffer_Release(&value); + + parcHashMap_Release(&x); +} + +LONGBOW_TEST_CASE(ObjectContract, parcHashMap_Equals) +{ + PARCBuffer *key = parcBuffer_WrapCString("key1"); + PARCBuffer *value = parcBuffer_WrapCString("value1"); + + PARCHashMap *x = parcHashMap_Create(); + parcHashMap_Put(x, key, value); + PARCHashMap *y = parcHashMap_Create(); + parcHashMap_Put(y, key, value); + PARCHashMap *z = parcHashMap_Create(); + parcHashMap_Put(z, key, value); + + PARCHashMap *u1 = parcHashMap_Create(); + + PARCHashMap *u2 = parcHashMap_Create(); + parcHashMap_Put(u2, key, value); + + parcObjectTesting_AssertEquals(x, y, z, u1, NULL); + + parcHashMap_Release(&x); + parcHashMap_Release(&y); + parcHashMap_Release(&z); + parcHashMap_Release(&u1); + parcHashMap_Release(&u2); + + parcBuffer_Release(&key); + parcBuffer_Release(&value); +} + +LONGBOW_TEST_CASE(ObjectContract, parcHashMap_HashCode_Empty) +{ + PARCHashMap *instance = parcHashMap_Create(); + + PARCHashCode code = parcHashMap_HashCode(instance); + + assertTrue(code == 0, "Expected 0, actual %" PRIPARCHashCode, code); + parcHashMap_Release(&instance); +} + +LONGBOW_TEST_CASE(ObjectContract, parcHashMap_HashCode_NonEmpty) +{ + PARCHashMap *instance = parcHashMap_Create(); + PARCBuffer *key = parcBuffer_WrapCString("key1"); + PARCBuffer *value = parcBuffer_WrapCString("value1"); + parcHashMap_Put(instance, key, value); + parcBuffer_Release(&key); + parcBuffer_Release(&value); + + PARCHashCode code = parcHashMap_HashCode(instance); + assertTrue(code != 0, "Expected a non-zero hash code, actual %" PRIPARCHashCode, code); + + parcHashMap_Release(&instance); +} + +LONGBOW_TEST_CASE(ObjectContract, parcHashMap_IsValid) +{ + PARCHashMap *instance = parcHashMap_Create(); + + PARCBuffer *key = parcBuffer_WrapCString("key1"); + PARCBuffer *value = parcBuffer_WrapCString("value1"); + parcHashMap_Put(instance, key, value); + assertTrue(parcHashMap_IsValid(instance), "Expected parcHashMap_Create to result in a valid instance."); + + parcHashMap_Release(&instance); + assertFalse(parcHashMap_IsValid(instance), "Expected parcHashMap_Create to result in an invalid instance."); + + parcBuffer_Release(&key); + parcBuffer_Release(&value); +} + +LONGBOW_TEST_CASE(ObjectContract, parcHashMap_AssertValid) +{ + PARCHashMap *instance = parcHashMap_Create(); + + PARCBuffer *key = parcBuffer_WrapCString("key1"); + PARCBuffer *value = parcBuffer_WrapCString("value1"); + parcHashMap_Put(instance, key, value); + parcHashMap_AssertValid(instance); + + parcBuffer_Release(&key); + parcBuffer_Release(&value); + parcHashMap_Release(&instance); +} + +LONGBOW_TEST_CASE(ObjectContract, parcHashMap_ToJSON) +{ + PARCHashMap *instance = parcHashMap_Create(); + PARCBuffer *key = parcBuffer_WrapCString("key1"); + PARCBuffer *value = parcBuffer_WrapCString("value1"); + parcHashMap_Put(instance, key, value); + + PARCJSON *json = parcHashMap_ToJSON(instance); + + parcJSON_Release(&json); + parcBuffer_Release(&key); + parcBuffer_Release(&value); + + parcHashMap_Release(&instance); +} + +LONGBOW_TEST_CASE(ObjectContract, parcHashMap_ToString) +{ + PARCHashMap *instance = parcHashMap_Create(); + PARCBuffer *key = parcBuffer_WrapCString("key1"); + PARCBuffer *value = parcBuffer_WrapCString("value1"); + parcHashMap_Put(instance, key, value); + + char *string = parcHashMap_ToString(instance); + + assertNotNull(string, "Expected non-NULL result from parcHashMap_ToString"); + + parcMemory_Deallocate(&string); + parcBuffer_Release(&key); + parcBuffer_Release(&value); + parcHashMap_Release(&instance); +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcHashMap_Put); + LONGBOW_RUN_TEST_CASE(Global, parcHashMap_PutN); + LONGBOW_RUN_TEST_CASE(Global, parcHashMap_Put_Replace); + LONGBOW_RUN_TEST_CASE(Global, parcHashMap_Get_NoValue); + LONGBOW_RUN_TEST_CASE(Global, parcHashMap_Contains_True); + LONGBOW_RUN_TEST_CASE(Global, parcHashMap_Contains_False); + LONGBOW_RUN_TEST_CASE(Global, parcHashMap_Remove); + LONGBOW_RUN_TEST_CASE(Global, parcHashMap_Remove_False); + LONGBOW_RUN_TEST_CASE(Global, parcHashMap_Resize); + LONGBOW_RUN_TEST_CASE(Global, parcHashMap_GetClusteringNumber); + LONGBOW_RUN_TEST_CASE(Global, parcHashMap_CreateValueIterator); + LONGBOW_RUN_TEST_CASE(Global, parcHashMap_CreateValueIterator_HasNext); + LONGBOW_RUN_TEST_CASE(Global, parcHashMap_CreateValueIterator_Next); + LONGBOW_RUN_TEST_CASE(Global, parcHashMap_KeyIterator); + LONGBOW_RUN_TEST_CASE(Global, parcHashMap_KeyIterator_HasNext); + LONGBOW_RUN_TEST_CASE(Global, parcHashMap_KeyIterator_Next); + LONGBOW_RUN_TEST_CASE(Global, parcHashMap_KeyIterator_Remove); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) { + parcSafeMemory_ReportAllocation(1); + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, parcHashMap_Put) +{ + PARCHashMap *instance = parcHashMap_Create(); + + PARCBuffer *key = parcBuffer_WrapCString("key1"); + PARCBuffer *value = parcBuffer_WrapCString("value1"); + + //size_t keyReferences = parcObject_GetReferenceCount(key); + size_t valueReferences = parcObject_GetReferenceCount(value); + + parcHashMap_Put(instance, key, value); + //M.S. Put() now results in a copy of the key. + //assertTrue(keyReferences + 1 == parcObject_GetReferenceCount(key), "Expected key reference to be incremented by 1."); + assertTrue(valueReferences + 1 == parcObject_GetReferenceCount(value), "Expected value reference to be incremented by 1."); + + PARCBuffer *actual = (PARCBuffer *) parcHashMap_Get(instance, key); + + assertTrue(parcBuffer_Equals(value, actual), "Expected value was not returned from Get"); + + parcBuffer_Release(&key); + parcBuffer_Release(&value); + + parcHashMap_Release(&instance); +} + +typedef struct { + int64_t number; +} _Int; + +static char * +_int_toString(const _Int *anInt) +{ + char *result = parcMemory_AllocateAndClear(22); + sprintf(result, "%" PRIi64 "", anInt->number); + return result; +} + +static PARCHashCode +_int_hashCode(const _Int *anInt) +{ + PARCHashCode result = anInt->number; + + return result; +} + +parcObject_ExtendPARCObject(_Int, NULL, NULL, _int_toString, NULL, NULL, _int_hashCode, NULL); + +parcObject_ImplementRelease(_int, _Int); + +static _Int * +_int_Create(int64_t anInt) +{ + _Int *_int = parcObject_CreateInstance(_Int); + + if (_int != NULL) { + _int->number = anInt; + } + + return _int; +} + +LONGBOW_TEST_CASE(Global, parcHashMap_GetClusteringNumber) +{ + size_t minimumSize = 100; + PARCHashMap *instance = parcHashMap_CreateCapacity(minimumSize); + + double maxLoadFactor = instance->maxLoadFactor; + + // Load a hash map up to its load-factor + size_t testRunSize = minimumSize * maxLoadFactor - 20; + srand(time(NULL)); + for (int i = 0; i < testRunSize; ++i) { + _Int *key = _int_Create(rand()); + PARCBuffer *value = parcBuffer_Allocate(sizeof(uint32_t)); + parcBuffer_PutUint32(value, 1000 + i); + parcHashMap_Put(instance, key, value); + parcBuffer_Release(&value); + _int_Release(&key); + } + + double currentClusteringNumber = parcHashMap_GetClusteringNumber(instance); + + if (currentClusteringNumber < 0.5) { + testWarn("Oddly low clustering number detected."); + } + + if (currentClusteringNumber > 1.5) { + testWarn("Oddly high clustering number detected."); + } + + // This will load up one bucket + for (int i = 0; i < 20; ++i) { + _Int *key = _int_Create(1 + (100 * i)); + PARCBuffer *value = parcBuffer_Allocate(sizeof(uint32_t)); + parcBuffer_PutUint32(value, 10 + i); + parcHashMap_Put(instance, key, value); + parcBuffer_Release(&value); + _int_Release(&key); + } + + currentClusteringNumber = parcHashMap_GetClusteringNumber(instance); + + parcHashMap_Release(&instance); + + if (currentClusteringNumber < 2.9) { + testWarn("Oddly low clustering number detected."); + } +} + +LONGBOW_TEST_CASE(Global, parcHashMap_Resize) +{ + size_t initialSize = 8; + PARCHashMap *instance = parcHashMap_CreateCapacity(initialSize); + + PARCBuffer *key = parcBuffer_Allocate(sizeof(uint32_t)); + PARCBuffer *value42 = parcBuffer_WrapCString("value42"); + double maxLoadFactor = instance->maxLoadFactor; + + // Load a hash map up to its load-factor + size_t testRunSize = initialSize * maxLoadFactor; + for (uint32_t i = 0; i < testRunSize; ++i) { + parcBuffer_PutUint32(key, i); + PARCBuffer *value = parcBuffer_Allocate(sizeof(uint32_t)); + parcBuffer_PutUint32(value, 1000 + i); + parcHashMap_Put(instance, parcBuffer_Flip(key), value); + parcBuffer_Release(&value); + } + assertTrue(parcHashMap_Size(instance) == testRunSize, "Expect the size to be %zu", testRunSize); + assertTrue(instance->capacity == initialSize, "Expect to have the original capacity"); + + // Test for expected values + for (uint32_t i = 0; i < testRunSize; ++i) { + parcBuffer_PutUint32(key, i); + PARCBuffer *value = parcBuffer_Allocate(sizeof(uint32_t)); + parcBuffer_PutUint32(value, 1000 + i); + const PARCBuffer *storedValue = parcHashMap_Get(instance, parcBuffer_Flip(key)); + assertTrue(parcBuffer_Equals(value, storedValue), "Expect looked up values to match"); + parcBuffer_Release(&value); + } + + // Add one more item to the the hash map, this should trigger an expansion + parcBuffer_PutUint32(key, 42); + parcHashMap_Put(instance, parcBuffer_Flip(key), value42); + assertTrue(parcHashMap_Size(instance) == testRunSize + 1, "Expect the size to be %zu", testRunSize); + assertTrue(instance->capacity == 2 * initialSize, "Expect to have the original capacity"); + + // Re-test value look ups to make sure the new hash map still maps correctly + for (uint32_t i = 0; i < testRunSize; ++i) { + parcBuffer_PutUint32(key, i); + PARCBuffer *value = parcBuffer_Allocate(sizeof(uint32_t)); + parcBuffer_PutUint32(value, 1000 + i); + const PARCBuffer *storedValue = parcHashMap_Get(instance, parcBuffer_Flip(key)); + assertTrue(parcBuffer_Equals(value, storedValue), "Expect looked up values to match"); + parcBuffer_Release(&value); + } + double averageBucketSize = parcHashMap_GetClusteringNumber(instance); + parcBuffer_PutUint32(key, 42); + const PARCBuffer *storedValue = parcHashMap_Get(instance, parcBuffer_Flip(key)); + assertTrue(parcBuffer_Equals(value42, storedValue), "Expect to get back value42"); + parcBuffer_Release(&value42); + assertTrue(parcHashMap_GetClusteringNumber(instance) <= averageBucketSize, + "Expect the average bucket size to be less then it was"); + + // Now test multiple expansions to make sure they happened are result in a valid hash map + size_t testCapacity = 1024; + // If we load up to (maxLoadFactor * testCapacity) + 1, the capacity should expand to 2 * testCapacity + testRunSize = (testCapacity * maxLoadFactor) + 1; + for (uint32_t i = 0; i < testRunSize; ++i) { + parcBuffer_PutUint32(key, i); + PARCBuffer *value = parcBuffer_Allocate(sizeof(uint32_t)); + parcBuffer_PutUint32(value, 1000 + i); + parcHashMap_Put(instance, parcBuffer_Flip(key), value); + parcBuffer_Release(&value); + if (i == (testRunSize - 2)) { + averageBucketSize = parcHashMap_GetClusteringNumber(instance); + } + } + assertTrue(instance->capacity == (2 * testCapacity), + "Expect capacity to be %zu got %zu", (2 * testCapacity), instance->capacity); + assertTrue(parcHashMap_GetClusteringNumber(instance) < averageBucketSize, + "Expect the average bucket size to be less then it was"); + + // Now test multiple contractions. + // If we remove all elements from index "smallSize" (eg. 8) up we will be left with a map of size smallSize, + // the map capacity should be contracting and, because the minimum load factor is 0.25 and the contraction + // is a divide by 2, the last contraction should be from capacity of "smallSize * 4" (32) to one + // of "smallSize * 2" (16) when size goes from "smallSize +1" (9) to "smallSize" (8). + // + size_t smallSize = 8; + for (uint32_t i = smallSize; i < testRunSize; ++i) { + parcBuffer_PutUint32(key, i); + parcBuffer_Flip(key); + PARCBuffer *value = parcBuffer_Allocate(sizeof(uint32_t)); + parcBuffer_PutUint32(value, 1000 + i); + const PARCBuffer *storedValue = parcHashMap_Get(instance, key); + assertTrue(parcBuffer_Equals(value, storedValue), "Expect looked up values to match"); + parcBuffer_Release(&value); + + assertTrue(parcHashMap_Remove(instance, key), "Expect Remove to succeed"); + } + assertTrue(instance->size == smallSize, + "Expect the hash map to have size %zu, got %zu", smallSize, instance->size) + assertTrue(instance->capacity == (smallSize * 2), + "Expect capacity to be %zu, got %zu", (smallSize * 2), instance->capacity); + + // Re-test value look ups to make sure the new hash map still maps correctly + for (uint32_t i = 0; i < smallSize; ++i) { + parcBuffer_PutUint32(key, i); + PARCBuffer *value = parcBuffer_Allocate(sizeof(uint32_t)); + parcBuffer_PutUint32(value, 1000 + i); + const PARCBuffer *storedValue = parcHashMap_Get(instance, parcBuffer_Flip(key)); + assertTrue(parcBuffer_Equals(value, storedValue), "Expect looked up values to match"); + parcBuffer_Release(&value); + } + + parcBuffer_Release(&key); + parcHashMap_Release(&instance); +} + +LONGBOW_TEST_CASE(Global, parcHashMap_PutN) +{ + size_t testRunSize = 100; + + PARCHashMap *instance = parcHashMap_CreateCapacity(testRunSize); + + PARCBuffer *key = parcBuffer_Allocate(sizeof(uint32_t)); + PARCBuffer *value = parcBuffer_WrapCString("value1"); + PARCBuffer *value42 = parcBuffer_WrapCString("value42"); + for (uint32_t i = 0; i < testRunSize * 2; ++i) { + parcBuffer_PutUint32(key, i); + parcHashMap_Put(instance, parcBuffer_Flip(key), value); + if (i == 42) { + parcHashMap_Put(instance, key, value42); + } + } + + parcBuffer_PutUint32(key, 42); + PARCBuffer *actual = (PARCBuffer *) parcHashMap_Get(instance, parcBuffer_Flip(key)); + assertTrue(parcBuffer_Equals(value42, actual), "Expect to get back value42"); + + parcBuffer_Release(&key); + parcBuffer_Release(&value); + parcBuffer_Release(&value42); + parcHashMap_Release(&instance); +} + +LONGBOW_TEST_CASE(Global, parcHashMap_Put_Replace) +{ + PARCHashMap *instance = parcHashMap_Create(); + + PARCBuffer *key = parcBuffer_WrapCString("key1"); + PARCBuffer *value1 = parcBuffer_WrapCString("value1"); + PARCBuffer *value2 = parcBuffer_WrapCString("value2"); + + parcHashMap_Put(instance, key, value1); + + parcHashMap_Put(instance, key, value2); + + PARCBuffer *actual = (PARCBuffer *) parcHashMap_Get(instance, key); + + assertTrue(parcBuffer_Equals(value2, actual), "Expected value was not returned from Get"); + + parcBuffer_Release(&key); + parcBuffer_Release(&value1); + parcBuffer_Release(&value2); + parcHashMap_Release(&instance); +} + +LONGBOW_TEST_CASE(Global, parcHashMap_Get_NoValue) +{ + PARCHashMap *instance = parcHashMap_Create(); + + PARCBuffer *key = parcBuffer_WrapCString("key1"); + + PARCBuffer *actual = (PARCBuffer *) parcHashMap_Get(instance, key); + + assertNull(actual, "Expected parcHashMap_Get to return NULL for non-existent key."); + + parcBuffer_Release(&key); + + parcHashMap_Release(&instance); +} + +LONGBOW_TEST_CASE(Global, parcHashMap_Contains_True) +{ + PARCHashMap *instance = parcHashMap_Create(); + + PARCBuffer *key = parcBuffer_WrapCString("key1"); + PARCBuffer *value = parcBuffer_WrapCString("value1"); + + parcHashMap_Put(instance, key, value); + + bool actual = parcHashMap_Contains(instance, key); + + assertTrue(actual, "Expected parcHashMap_Contains to return true"); + + parcBuffer_Release(&key); + parcBuffer_Release(&value); + + parcHashMap_Release(&instance); +} + +LONGBOW_TEST_CASE(Global, parcHashMap_Contains_False) +{ + PARCHashMap *instance = parcHashMap_Create(); + + PARCBuffer *key = parcBuffer_WrapCString("key1"); + + bool actual = parcHashMap_Contains(instance, key); + + assertFalse(actual, "Expected parcHashMap_Contains to return NULL for non-existent key."); + + parcBuffer_Release(&key); + + parcHashMap_Release(&instance); +} + +LONGBOW_TEST_CASE(Global, parcHashMap_Remove) +{ + PARCHashMap *instance = parcHashMap_Create(); + + PARCBuffer *key = parcBuffer_WrapCString("key1"); + PARCBuffer *value = parcBuffer_WrapCString("value1"); + + parcHashMap_Put(instance, key, value); + + bool actual = parcHashMap_Remove(instance, key); + + assertTrue(actual, "Expected parcHashMap_Remove to return true."); + + parcBuffer_Release(&key); + parcBuffer_Release(&value); + + parcHashMap_Release(&instance); +} + +LONGBOW_TEST_CASE(Global, parcHashMap_Remove_False) +{ + PARCHashMap *instance = parcHashMap_Create(); + + PARCBuffer *key = parcBuffer_WrapCString("key1"); + PARCBuffer *key2 = parcBuffer_WrapCString("key2"); + PARCBuffer *value = parcBuffer_WrapCString("value1"); + + parcHashMap_Put(instance, key, value); + + bool actual = parcHashMap_Remove(instance, key2); + + assertFalse(actual, "Expected parcHashMap_Remove to return false."); + + parcBuffer_Release(&key); + parcBuffer_Release(&key2); + parcBuffer_Release(&value); + + parcHashMap_Release(&instance); +} + +LONGBOW_TEST_CASE(Global, parcHashMap_CreateValueIterator) +{ + PARCHashMap *instance = parcHashMap_Create(); + + PARCBuffer *key = parcBuffer_WrapCString("key1"); + PARCBuffer *value = parcBuffer_WrapCString("value1"); + + parcHashMap_Put(instance, key, value); + + PARCIterator *iterator = parcHashMap_CreateValueIterator(instance); + + assertNotNull(iterator, "Expected parcHashMap_ValueIterator to return non-null result"); + + parcIterator_Release(&iterator); + parcBuffer_Release(&key); + parcBuffer_Release(&value); + + parcHashMap_Release(&instance); +} + +LONGBOW_TEST_CASE(Global, parcHashMap_CreateValueIterator_HasNext) +{ + PARCHashMap *instance = parcHashMap_Create(); + + PARCBuffer *key = parcBuffer_WrapCString("key1"); + PARCBuffer *value = parcBuffer_WrapCString("value1"); + + parcHashMap_Put(instance, key, value); + + PARCIterator *iterator = parcHashMap_CreateValueIterator(instance); + + assertTrue(parcIterator_HasNext(iterator), "Expected parcIterator_HasNext to return true"); + + parcIterator_Release(&iterator); + parcBuffer_Release(&key); + parcBuffer_Release(&value); + + parcHashMap_Release(&instance); +} + +LONGBOW_TEST_CASE(Global, parcHashMap_CreateValueIterator_Next) +{ + PARCHashMap *instance = parcHashMap_Create(); + + PARCBuffer *key1 = parcBuffer_WrapCString("key1"); + PARCBuffer *value1 = parcBuffer_WrapCString("1"); + PARCBuffer *key2 = parcBuffer_WrapCString("key2"); + PARCBuffer *value2 = parcBuffer_WrapCString("2"); + PARCBuffer *key3 = parcBuffer_WrapCString("key3"); + PARCBuffer *value3 = parcBuffer_WrapCString("3"); + PARCBuffer *key4 = parcBuffer_WrapCString("key4"); + PARCBuffer *value4 = parcBuffer_WrapCString("4"); + + parcHashMap_Put(instance, key1, value1); + parcHashMap_Put(instance, key2, value2); + parcHashMap_Put(instance, key3, value3); + parcHashMap_Put(instance, key4, value4); + + PARCIterator *iterator = parcHashMap_CreateValueIterator(instance); + + while (parcIterator_HasNext(iterator)) { + PARCBuffer *actual = parcIterator_Next(iterator); + assertNotNull(actual, "Expected parcIterator_Next to return non-null"); + assertTrue(parcBuffer_Remaining(actual) > 0, "The same value appeared more than once in the iteration"); + parcBuffer_SetPosition(actual, parcBuffer_Limit(actual)); + } + parcIterator_Release(&iterator); + + parcBuffer_Release(&key1); + parcBuffer_Release(&value1); + parcBuffer_Release(&key2); + parcBuffer_Release(&value2); + parcBuffer_Release(&key3); + parcBuffer_Release(&value3); + parcBuffer_Release(&key4); + parcBuffer_Release(&value4); + + parcHashMap_Release(&instance); +} + +LONGBOW_TEST_CASE(Global, parcHashMap_KeyIterator) +{ + PARCHashMap *instance = parcHashMap_Create(); + + PARCBuffer *key = parcBuffer_WrapCString("key1"); + PARCBuffer *value = parcBuffer_WrapCString("value1"); + + parcHashMap_Put(instance, key, value); + + PARCIterator *iterator = parcHashMap_CreateKeyIterator(instance); + + assertNotNull(iterator, "Expected parcHashMap_KeyIterator to return non-null result"); + + parcIterator_Release(&iterator); + parcBuffer_Release(&key); + parcBuffer_Release(&value); + + parcHashMap_Release(&instance); +} + +LONGBOW_TEST_CASE(Global, parcHashMap_KeyIterator_HasNext) +{ + PARCHashMap *instance = parcHashMap_Create(); + + PARCBuffer *key = parcBuffer_WrapCString("key1"); + PARCBuffer *value = parcBuffer_WrapCString("value1"); + + parcHashMap_Put(instance, key, value); + + PARCIterator *iterator = parcHashMap_CreateKeyIterator(instance); + + assertTrue(parcIterator_HasNext(iterator), "Expected parcIterator_HasNext to return true"); + + parcIterator_Release(&iterator); + parcBuffer_Release(&key); + parcBuffer_Release(&value); + + parcHashMap_Release(&instance); +} + +LONGBOW_TEST_CASE(Global, parcHashMap_KeyIterator_Next) +{ + PARCHashMap *instance = parcHashMap_Create(); + + PARCBuffer *key1 = parcBuffer_WrapCString("key1"); + PARCBuffer *value1 = parcBuffer_WrapCString("1"); + PARCBuffer *key2 = parcBuffer_WrapCString("key2"); + PARCBuffer *value2 = parcBuffer_WrapCString("2"); + PARCBuffer *key3 = parcBuffer_WrapCString("key3"); + PARCBuffer *value3 = parcBuffer_WrapCString("3"); + PARCBuffer *key4 = parcBuffer_WrapCString("key4"); + PARCBuffer *value4 = parcBuffer_WrapCString("4"); + + parcHashMap_Put(instance, key1, value1); + parcHashMap_Put(instance, key2, value2); + parcHashMap_Put(instance, key3, value3); + parcHashMap_Put(instance, key4, value4); + + PARCIterator *iterator = parcHashMap_CreateKeyIterator(instance); + + while (parcIterator_HasNext(iterator)) { + PARCBuffer *actual = parcIterator_Next(iterator); + assertNotNull(actual, "Expected parcIterator_Next to return non-null"); + assertTrue(parcBuffer_Remaining(actual) > 0, "The same value appeared more than once in the iteration"); + parcBuffer_SetPosition(actual, parcBuffer_Limit(actual)); + } + parcIterator_Release(&iterator); + + parcBuffer_Release(&key1); + parcBuffer_Release(&value1); + parcBuffer_Release(&key2); + parcBuffer_Release(&value2); + parcBuffer_Release(&key3); + parcBuffer_Release(&value3); + parcBuffer_Release(&key4); + parcBuffer_Release(&value4); + + parcHashMap_Release(&instance); +} + +LONGBOW_TEST_CASE(Global, parcHashMap_KeyIterator_Remove) +{ + PARCHashMap *instance = parcHashMap_Create(); + + PARCBuffer *key1 = parcBuffer_WrapCString("key1"); + PARCBuffer *value1 = parcBuffer_WrapCString("1"); + PARCBuffer *key2 = parcBuffer_WrapCString("key2"); + PARCBuffer *value2 = parcBuffer_WrapCString("2"); + PARCBuffer *key3 = parcBuffer_WrapCString("key3"); + PARCBuffer *value3 = parcBuffer_WrapCString("3"); + PARCBuffer *key4 = parcBuffer_WrapCString("key4"); + PARCBuffer *value4 = parcBuffer_WrapCString("4"); + + parcHashMap_Put(instance, key1, value1); + parcHashMap_Put(instance, key2, value2); + parcHashMap_Put(instance, key3, value3); + parcHashMap_Put(instance, key4, value4); + + assertTrue(parcHashMap_Size(instance) == 4, "Expected 4, actual %zd", parcHashMap_Size(instance)); + PARCIterator *iterator = parcHashMap_CreateKeyIterator(instance); + + while (parcIterator_HasNext(iterator)) { + PARCBuffer *key = parcBuffer_Acquire(parcIterator_Next(iterator)); + parcIterator_Remove(iterator); + assertNull(parcHashMap_Get(instance, key), "Expected deleted entry to not be gettable."); + parcBuffer_Release(&key); + } + parcIterator_Release(&iterator); + + assertTrue(parcHashMap_Size(instance) == 0, "Expected 0, actual %zd", parcHashMap_Size(instance)); + parcBuffer_Release(&key1); + parcBuffer_Release(&value1); + parcBuffer_Release(&key2); + parcBuffer_Release(&value2); + parcBuffer_Release(&key3); + parcBuffer_Release(&value3); + parcBuffer_Release(&key4); + parcBuffer_Release(&value4); + + parcHashMap_Release(&instance); +} + +LONGBOW_TEST_FIXTURE(Static) +{ + LONGBOW_RUN_TEST_CASE(Static, parcHashMapEntry); +} + +LONGBOW_TEST_FIXTURE_SETUP(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Static) +{ + if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) { + parcSafeMemory_ReportAllocation(1); + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Static, parcHashMapEntry) +{ + PARCBuffer *key = parcBuffer_WrapCString("key1"); + PARCBuffer *value = parcBuffer_WrapCString("value1"); + + _PARCHashMapEntry *instance = _parcHashMapEntry_Create(key, value); + parcBuffer_Release(&key); + parcBuffer_Release(&value); + + _parcHashMapEntry_Release(&instance); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_HashMap); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_InputStream.c b/libparc/parc/algol/test/test_parc_InputStream.c new file mode 100755 index 00000000..46d47862 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_InputStream.c @@ -0,0 +1,109 @@ +/* + * 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 "../parc_InputStream.c" + +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(parc_InputStream) +{ + // 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(parc_InputStream) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_InputStream) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcInputStream); + LONGBOW_RUN_TEST_CASE(Global, parcInputStream_Acquire); + LONGBOW_RUN_TEST_CASE(Global, parcInputStream_Read); + LONGBOW_RUN_TEST_CASE(Global, parcInputStream_Release); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, parcInputStream) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Global, parcInputStream_Acquire) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Global, parcInputStream_Read) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Global, parcInputStream_Release) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, parcInputStream_Finalize); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, parcInputStream_Finalize) +{ + testUnimplemented(""); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_InputStream); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_Iterator.c b/libparc/parc/algol/test/test_parc_Iterator.c new file mode 100644 index 00000000..d5778721 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_Iterator.c @@ -0,0 +1,192 @@ +/* + * 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 "../parc_Iterator.c" + +#include <inttypes.h> +#include <stdio.h> + +#include <parc/algol/parc_Buffer.h> +#include <parc/algol/parc_SafeMemory.h> +#include <parc/testing/parc_ObjectTesting.h> +#include <parc/testing/parc_MemoryTesting.h> + +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(parc_Iterator) +{ + // 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(CreateAcquireRelease); + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_Iterator) +{ + 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(parc_Iterator) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(CreateAcquireRelease) +{ + LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, parcIterator_CreateAcquireRelease); +} + +LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease) +{ + if (!parcMemoryTesting_ExpectedOutstanding(0, "%s", longBowTestCase_GetName(testCase))) { + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +static uint64_t _state; + +static void * +init(PARCObject *object __attribute__((unused))) +{ + _state = 0; + return &_state; +} + +static bool +hasNext(PARCObject *object __attribute__((unused)), void *state) +{ + uint64_t *value = (uint64_t *) state; + return (*value < 5); +} + +static void * +next(PARCObject *object __attribute__((unused)), void *state) +{ + uint64_t *value = (uint64_t *) state; + + (*value)++; + return state; +} + +static void +removex(PARCObject *object __attribute__((unused)), void **state) +{ +} + +static void * +getElement(PARCObject *object __attribute__((unused)), void *state) +{ + uint64_t *value = (uint64_t *) state; + return (void *) *value; +} + +static void +fini(PARCObject *object __attribute__((unused)), void *state __attribute__((unused))) +{ +} + +static void +assertValid(const void *state __attribute__((unused))) +{ +} + +LONGBOW_TEST_CASE(CreateAcquireRelease, parcIterator_CreateAcquireRelease) +{ + PARCBuffer *buffer = parcBuffer_Allocate(1); + + PARCIterator *iterator = parcIterator_Create(buffer, init, hasNext, next, removex, getElement, fini, assertValid); + + parcObjectTesting_AssertAcquireReleaseContract(parcIterator_Acquire, iterator); + parcBuffer_Release(&buffer); + parcIterator_Release(&iterator); +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcIterator_HasNext); + LONGBOW_RUN_TEST_CASE(Global, parcIterator_Next); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + bool leaked = parcMemoryTesting_ExpectedOutstanding(0, "%s leaks memory \n", longBowTestCase_GetName(testCase)) != true; + if (leaked) { + parcSafeMemory_ReportAllocation(STDOUT_FILENO); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, parcIterator_HasNext) +{ + PARCBuffer *buffer = parcBuffer_Allocate(1); + + PARCIterator *iterator = parcIterator_Create(buffer, init, hasNext, next, removex, getElement, fini, assertValid); + + while (parcIterator_HasNext(iterator)) { + uint64_t value = (uint64_t) parcIterator_Next(iterator); + printf("%" PRIu64 "\n", value); + } + parcBuffer_Release(&buffer); + parcIterator_Release(&iterator); +} + +LONGBOW_TEST_CASE(Global, parcIterator_Next) +{ + PARCBuffer *buffer = parcBuffer_Allocate(1); + + PARCIterator *iterator = parcIterator_Create(buffer, init, hasNext, next, removex, getElement, fini, assertValid); + + while (parcIterator_HasNext(iterator)) { + uint64_t value = (uint64_t) parcIterator_Next(iterator); + printf("%" PRIu64 "\n", value); + } + parcBuffer_Release(&buffer); + parcIterator_Release(&iterator); +} + +LONGBOW_TEST_CASE(Local, _finalize) +{ + testUnimplemented(""); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Iterator); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_JSON.c b/libparc/parc/algol/test/test_parc_JSON.c new file mode 100644 index 00000000..d1825319 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_JSON.c @@ -0,0 +1,690 @@ +/* + * 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 "../parc_JSON.c" +#include "../parc_JSONPair.c" + +#include <stdio.h> +#include <fcntl.h> +#include <inttypes.h> + +#include <LongBow/unit-test.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. + + +#include "../parc_List.h" +#include "../parc_ArrayList.h" +#include "../parc_SafeMemory.h" +#include "../parc_Memory.h" +#include <parc/testing/parc_ObjectTesting.h> + +LONGBOW_TEST_RUNNER(parc_JSON) +{ + // 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(Static); + LONGBOW_RUN_TEST_FIXTURE(JSON); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_JSON) +{ + 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(parc_JSON) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(JSON) +{ + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_CreateRelease); + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_Equals); + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_HashCode); + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_Copy); + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_Add); + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_GetMembers); + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_GetPairByName); + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_GetValueByName); + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_GetPairByIndex); + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_GetValueByIndex); + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_BuildString); + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_ToString); + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_ToCompactString); + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_GetByPath); + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_GetByPath_BadArrayIndex); + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_GetByPath_DeadEndPath); + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_ParseString); + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_ParseBuffer_WithExcess); + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_Display); + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_AddString); + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_AddObject); + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_AddInteger); + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_AddBoolean); + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_AddArray); + LONGBOW_RUN_TEST_CASE(JSON, parcJSON_AddValue); +} + +typedef struct { + PARCJSON *json; + char *expected; + char *compactExpected; +} TestData; + +LONGBOW_TEST_FIXTURE_SETUP(JSON) +{ + TestData *data = parcMemory_Allocate(sizeof(TestData)); + + char *temp = "{ \"string\" : \"foo\\/bar\", \"null\" : null, \"true\" : true, \"false\" : false, \"integer\" : 31415, \"float\" : 3.141500, \"json\" : { \"string\" : \"foo\\/bar\" }, \"array\" : [ null, false, true, 31415, \"string\", [ null, false, true, 31415, \"string\" ], { } ] }"; + data->expected = parcMemory_StringDuplicate(temp, strlen(temp)); + + temp = "{\"string\":\"foo/bar\",\"null\":null,\"true\":true,\"false\":false,\"integer\":31415,\"float\":3.141500,\"json\":{\"string\":\"foo/bar\"},\"array\":[null,false,true,31415,\"string\",[null,false,true,31415,\"string\"],{}]}"; + data->compactExpected = parcMemory_StringDuplicate(temp, strlen(temp)); + + data->json = parcJSON_ParseString(temp); + + longBowTestCase_SetClipBoardData(testCase, data); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(JSON) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + parcJSON_Release(&data->json); + parcMemory_Deallocate(&data->expected); + parcMemory_Deallocate(&data->compactExpected); + + parcMemory_Deallocate(&data); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + if (outstandingAllocations != 0) { + printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + + +LONGBOW_TEST_CASE(JSON, parcJSON_CreateRelease) +{ + PARCJSON *json = parcJSON_Create(); + + parcJSON_Release(&json); + assertNull(json, "Expected the NULL pointer side-effect of Release."); +} + +LONGBOW_TEST_CASE(JSON, parcJSON_Copy) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCJSON *copy = parcJSON_Copy(data->json); + + assertTrue(parcJSON_Equals(data->json, copy), "Expect copy to equal original"); + + parcJSON_Release(©); +} + +LONGBOW_TEST_CASE(JSON, parcJSON_HashCode) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCHashCode expected = parcHashCode_Hash((uint8_t *) data->compactExpected, strlen(data->compactExpected)); + + PARCHashCode hashCode = parcJSON_HashCode(data->json); + + assertTrue(hashCode == expected, "Expect correct hash code"); +} + +LONGBOW_TEST_CASE(JSON, parcJSON_Add) +{ + PARCJSON *json = parcJSON_Create(); + { + PARCBuffer *string = parcBuffer_WrapCString("string"); + PARCJSONValue *stringValue = parcJSONValue_CreateFromString(string); + PARCBuffer *stringName = parcBuffer_WrapCString("string"); + PARCJSONPair *pair = parcJSONPair_Create(stringName, stringValue); + parcJSON_AddPair(json, pair); + parcJSONPair_Release(&pair); + parcBuffer_Release(&stringName); + parcJSONValue_Release(&stringValue); + parcBuffer_Release(&string); + } + { + PARCBuffer *name = parcBuffer_WrapCString("null"); + PARCJSONValue *value = parcJSONValue_CreateFromNULL(); + PARCJSONPair *pair = parcJSONPair_Create(name, value); + parcJSON_AddPair(json, pair); + parcJSONPair_Release(&pair); + parcBuffer_Release(&name); + parcJSONValue_Release(&value); + } + { + PARCBuffer *name = parcBuffer_WrapCString("true"); + PARCJSONValue *value = parcJSONValue_CreateFromBoolean(true); + PARCJSONPair *pair = parcJSONPair_Create(name, value); + parcJSON_AddPair(json, pair); + parcJSONPair_Release(&pair); + parcBuffer_Release(&name); + parcJSONValue_Release(&value); + } + { + PARCBuffer *name = parcBuffer_WrapCString("false"); + PARCJSONValue *value = parcJSONValue_CreateFromBoolean(false); + PARCJSONPair *pair = parcJSONPair_Create(name, value); + parcJSON_AddPair(json, pair); + parcJSONPair_Release(&pair); + parcBuffer_Release(&name); + parcJSONValue_Release(&value); + } + { + PARCBuffer *name = parcBuffer_WrapCString("integer"); + PARCJSONValue *value = parcJSONValue_CreateFromInteger(31415); + PARCJSONPair *pair = parcJSONPair_Create(name, value); + parcJSON_AddPair(json, pair); + parcJSONPair_Release(&pair); + parcBuffer_Release(&name); + parcJSONValue_Release(&value); + } + { + PARCBuffer *name = parcBuffer_WrapCString("float"); + PARCJSONValue *value = parcJSONValue_CreateFromFloat(3.1415); + PARCJSONPair *pair = parcJSONPair_Create(name, value); + parcJSON_AddPair(json, pair); + parcJSONPair_Release(&pair); + parcBuffer_Release(&name); + parcJSONValue_Release(&value); + } + + parcJSON_Release(&json); +} + +LONGBOW_TEST_CASE(JSON, parcJSON_GetMembers) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + char *s = parcJSON_ToString(data->json); + parcMemory_Deallocate((void **) &s); + + PARCList *members = parcJSON_GetMembers(data->json); + assertTrue(parcList_Size(members) == 8, "Expected 8, actual %zd", parcList_Size(members)); +} + +LONGBOW_TEST_CASE(JSON, parcJSON_GetPairByName) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + int expected = 31415; + const PARCJSONPair *pair = parcJSON_GetPairByName(data->json, "integer"); + + PARCBuffer *name = parcJSONPair_GetName(pair); + PARCJSONValue *value = parcJSONPair_GetValue(pair); + + int64_t actual = parcJSONValue_GetInteger(value); + + PARCBuffer *expectedName = parcBuffer_WrapCString("integer"); + + assertTrue(parcBuffer_Equals(expectedName, name), + "Expected 'integer', actual '%s'", (char *) parcBuffer_ToString(name)); + + assertTrue(expected == actual, "Expected %d, actual %" PRIi64 "", expected, actual); + + parcBuffer_Release(&expectedName); +} + +LONGBOW_TEST_CASE(JSON, parcJSON_GetValueByName) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + int expected = 31415; + const PARCJSONValue *value = parcJSON_GetValueByName(data->json, "integer"); + + int64_t actual = parcJSONValue_GetInteger(value); + + PARCBuffer *expectedName = parcBuffer_WrapCString("integer"); + + assertTrue(expected == actual, "Expected %d, actual %" PRIi64 "", expected, actual); + + parcBuffer_Release(&expectedName); +} + +LONGBOW_TEST_CASE(JSON, parcJSON_GetPairByIndex) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCJSONPair *pair = parcJSON_GetPairByIndex(data->json, 0); + PARCBuffer *name = parcJSONPair_GetName(pair); + PARCBuffer *expectedName = parcBuffer_WrapCString("string"); + assertTrue(parcBuffer_Equals(expectedName, name), + "Expected 'string', actual '%s'", (char *) parcBuffer_ToString(name)); + parcBuffer_Release(&expectedName); + + pair = parcJSON_GetPairByIndex(data->json, 1); + name = parcJSONPair_GetName(pair); + expectedName = parcBuffer_WrapCString("null"); + assertTrue(parcBuffer_Equals(expectedName, name), + "Expected 'null', actual '%s'", (char *) parcBuffer_ToString(name)); + parcBuffer_Release(&expectedName); + + pair = parcJSON_GetPairByIndex(data->json, 2); + name = parcJSONPair_GetName(pair); + expectedName = parcBuffer_WrapCString("true"); + assertTrue(parcBuffer_Equals(expectedName, name), + "Expected 'true', actual '%s'", (char *) parcBuffer_ToString(name)); + parcBuffer_Release(&expectedName); + + pair = parcJSON_GetPairByIndex(data->json, 3); + name = parcJSONPair_GetName(pair); + expectedName = parcBuffer_WrapCString("false"); + assertTrue(parcBuffer_Equals(expectedName, name), + "Expected 'false', actual '%s'", (char *) parcBuffer_ToString(name)); + parcBuffer_Release(&expectedName); + + pair = parcJSON_GetPairByIndex(data->json, 4); + name = parcJSONPair_GetName(pair); + expectedName = parcBuffer_WrapCString("integer"); + assertTrue(parcBuffer_Equals(expectedName, name), + "Expected 'integer', actual '%s'", (char *) parcBuffer_ToString(name)); + parcBuffer_Release(&expectedName); + + pair = parcJSON_GetPairByIndex(data->json, 5); + name = parcJSONPair_GetName(pair); + expectedName = parcBuffer_WrapCString("float"); + assertTrue(parcBuffer_Equals(expectedName, name), + "Expected 'float', actual '%s'", (char *) parcBuffer_ToString(name)); + parcBuffer_Release(&expectedName); + + pair = parcJSON_GetPairByIndex(data->json, 6); + name = parcJSONPair_GetName(pair); + expectedName = parcBuffer_WrapCString("json"); + assertTrue(parcBuffer_Equals(expectedName, name), + "Expected 'json', actual '%s'", (char *) parcBuffer_ToString(name)); + parcBuffer_Release(&expectedName); + + pair = parcJSON_GetPairByIndex(data->json, 7); + name = parcJSONPair_GetName(pair); + expectedName = parcBuffer_WrapCString("array"); + assertTrue(parcBuffer_Equals(expectedName, name), + "Expected 'array', actual '%s'", (char *) parcBuffer_ToString(name)); + parcBuffer_Release(&expectedName); +} + +LONGBOW_TEST_CASE(JSON, parcJSON_GetValueByIndex) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCJSONValue *value = parcJSON_GetValueByIndex(data->json, 0); + assertTrue(parcJSONValue_IsString(value), + "Expected value to be type string"); + + value = parcJSON_GetValueByIndex(data->json, 1); + assertTrue(parcJSONValue_IsNull(value), + "Expected value to be type string"); + + value = parcJSON_GetValueByIndex(data->json, 2); + assertTrue(parcJSONValue_IsBoolean(value), + "Expected value to be type string"); + + value = parcJSON_GetValueByIndex(data->json, 3); + assertTrue(parcJSONValue_IsBoolean(value), + "Expected value to be type string"); + + value = parcJSON_GetValueByIndex(data->json, 4); + assertTrue(parcJSONValue_IsNumber(value), + "Expected value to be type string"); + + value = parcJSON_GetValueByIndex(data->json, 5); + assertTrue(parcJSONValue_IsNumber(value), + "Expected value to be type string"); + + value = parcJSON_GetValueByIndex(data->json, 6); + assertTrue(parcJSONValue_IsJSON(value), + "Expected value to be type string"); + + value = parcJSON_GetValueByIndex(data->json, 7); + assertTrue(parcJSONValue_IsArray(value), + "Expected value to be type string"); +} + +LONGBOW_TEST_CASE(JSON, parcJSON_BuildString) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBufferComposer *composer = parcBufferComposer_Create(); + parcJSON_BuildString(data->json, composer, false); + + PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); + char *actual = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + parcBufferComposer_Release(&composer); + + assertTrue(strcmp(data->expected, actual) == 0, "Expected %s, actual %s", data->expected, actual); + parcMemory_Deallocate((void **) &actual); + + composer = parcBufferComposer_Create(); + parcJSON_BuildString(data->json, composer, true); + + tempBuffer = parcBufferComposer_ProduceBuffer(composer); + actual = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + parcBufferComposer_Release(&composer); + + assertTrue(strcmp(data->compactExpected, actual) == 0, "Expected %s, actual %s", data->compactExpected, actual); + parcMemory_Deallocate((void **) &actual); +} + +LONGBOW_TEST_CASE(JSON, parcJSON_ToString) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + char *actual = parcJSON_ToString(data->json); + assertTrue(strcmp(data->expected, actual) == 0, "Expected %s, actual %s", data->expected, actual); + + parcMemory_Deallocate((void **) &actual); +} + +LONGBOW_TEST_CASE(JSON, parcJSON_ToCompactString) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + char *actual = parcJSON_ToCompactString(data->json); + assertTrue(strcmp(data->compactExpected, actual) == 0, "Expected %s, actual %s", data->expected, actual); + + parcMemory_Deallocate((void **) &actual); +} + +LONGBOW_TEST_CASE(JSON, parcJSON_GetByPath) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCJSON *json = data->json; + + char *s = parcJSON_ToString(json); + printf("%s\n", s); + parcMemory_Deallocate((void **) &s); + + const PARCJSONValue *value = parcJSON_GetByPath(json, "/string"); + assertTrue(parcJSONValue_IsString(value), "Expected /string to be a string type."); + value = parcJSON_GetByPath(json, "/null"); + assertTrue(parcJSONValue_IsNull(value), "Expected /null to be a null type."); + value = parcJSON_GetByPath(json, "/true"); + assertTrue(parcJSONValue_IsBoolean(value), "Expected /true to be a boolean type."); + value = parcJSON_GetByPath(json, "/integer"); + assertTrue(parcJSONValue_IsNumber(value), "Expected /integer to be a number type."); + value = parcJSON_GetByPath(json, "/float"); + assertTrue(parcJSONValue_IsNumber(value), "Expected /float to be a number type."); + value = parcJSON_GetByPath(json, "/array"); + assertTrue(parcJSONValue_IsArray(value), "Expected /array to be an array type."); + value = parcJSON_GetByPath(json, "/nonexistent"); + assertNull(value, "Expected /nonexistent to be NULL"); + + value = parcJSON_GetByPath(json, "/array/1"); + assertTrue(parcJSONValue_IsBoolean(value), "Expected /array/0 to be a boolean type."); + + value = parcJSON_GetByPath(json, "/array/5"); + assertTrue(parcJSONValue_IsArray(value), "Expected /array/5 to be an array type."); + + assertNotNull(value, "Expected non-null pair"); +} + +LONGBOW_TEST_CASE(JSON, parcJSON_GetByPath_BadArrayIndex) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + const PARCJSONValue *value = parcJSON_GetByPath(data->json, "/array/100"); + assertNull(value, "Expected null value return from parcJSON_GetByPath"); +} + +LONGBOW_TEST_CASE(JSON, parcJSON_GetByPath_DeadEndPath) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + const PARCJSONValue *value = parcJSON_GetByPath(data->json, "/string/foo"); + assertNull(value, "Expected null value return from parcJSON_GetByPath"); +} + +LONGBOW_TEST_CASE(JSON, parcJSON_Equals) +{ + PARCJSON *x = parcJSON_ParseString("{ \"string\" : \"xyzzy\" }"); + PARCJSON *y = parcJSON_ParseString("{ \"string\" : \"xyzzy\" }"); + PARCJSON *z = parcJSON_ParseString("{ \"string\" : \"xyzzy\" }"); + + PARCJSON *notEqual1 = parcJSON_ParseString("{ \"string\" : \"string\" }"); + + PARCJSON *notEqual2 = parcJSON_ParseString("{ \"string\" : \"xyzzy\", \"integer\" : 1 }"); + + parcObjectTesting_AssertEqualsFunction(parcJSON_Equals, x, y, z, notEqual1, notEqual2); + + parcJSON_Release(&x); + parcJSON_Release(&y); + parcJSON_Release(&z); + parcJSON_Release(¬Equal1); + parcJSON_Release(¬Equal2); +} + +LONGBOW_TEST_CASE(JSON, parcJSON_Display) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + parcJSON_Display(data->json, 0); +} + +LONGBOW_TEST_CASE(JSON, parcJSON_ParseString) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCJSON *json = parcJSON_ParseString(data->expected); + + char *actual = parcJSON_ToString(json); + + assertTrue(strcmp(data->expected, actual) == 0, "Expected %s, actual %s", data->expected, actual); + + parcMemory_Deallocate((void **) &actual); + + parcJSON_Release(&json); +} + +LONGBOW_TEST_CASE(JSON, parcJSON_ParseBuffer_WithExcess) +{ + char *string = "{ \"string\" : \"string\", \"null\" : null, \"true\" : true, \"false\" : false, \"integer\" : 31415, \"float\" : 3.141500, \"array\" : [ null, false, true, 31415, \"string\", [ null, false, true, 31415, \"string\" ], { } ] }Xhowdy"; + PARCBuffer *buffer = parcBuffer_WrapCString((char *) string); + + PARCJSON *json = parcJSON_ParseBuffer(buffer); + + char actual = parcBuffer_GetUint8(buffer); + assertTrue(actual == 'X', "Expected buffer position to point to X, actual %x", actual); + + parcBuffer_Release(&buffer); + parcJSON_Release(&json); +} + +LONGBOW_TEST_CASE(JSON, parcJSON_AddString) +{ + PARCJSON *json = parcJSON_Create(); + + char *expectedName = "string"; + char *expectedValue = "value"; + + parcJSON_AddString(json, expectedName, expectedValue); + + const PARCJSONPair *pair = parcJSON_GetPairByName(json, "string"); + PARCBuffer *actualName = parcJSONPair_GetName(pair); + PARCJSONValue *actualValue = parcJSONPair_GetValue(pair); + + assertTrue(strcmp(expectedName, parcBuffer_Overlay(actualName, 0)) == 0, + "Expected name %s, actual %s", + expectedName, + parcBuffer_ToString(actualName)); + assertTrue(strcmp(expectedValue, parcBuffer_Overlay(parcJSONValue_GetString(actualValue), 0)) == 0, + "Expected value %s, actual %s", + expectedValue, + parcJSONValue_ToString(actualValue)); + + parcJSON_Release(&json); +} + +LONGBOW_TEST_CASE(JSON, parcJSON_AddObject) +{ + PARCJSON *json = parcJSON_Create(); + + PARCJSON *expectedValue = parcJSON_ParseString("{ \"string\" : \"xyzzy\" }"); + parcJSON_AddObject(json, "object", expectedValue); + + char *expectedName = "object"; + const PARCJSONPair *pair = parcJSON_GetPairByName(json, expectedName); + + PARCBuffer *actualName = parcJSONPair_GetName(pair); + PARCJSONValue *actualValue = parcJSONPair_GetValue(pair); + + assertTrue(strcmp(expectedName, parcBuffer_Overlay(actualName, 0)) == 0, + "Expected name %s, actual %s", expectedName, (char *) parcBuffer_ToString(actualName)); + + assertTrue(parcJSON_Equals(expectedValue, parcJSONValue_GetJSON(actualValue)), + "Expected value did not match the actual value."); + + parcJSON_Release(&expectedValue); + parcJSON_Release(&json); +} + +LONGBOW_TEST_CASE(JSON, parcJSON_AddInteger) +{ + PARCJSON *json = parcJSON_Create(); + + char *expectedName = "integer"; + uint64_t expectedValue = 12345; + + parcJSON_AddInteger(json, expectedName, expectedValue); + + const PARCJSONPair *pair = parcJSON_GetPairByName(json, expectedName); + + PARCBuffer *actualName = parcJSONPair_GetName(pair); + PARCJSONValue *actualValue = parcJSONPair_GetValue(pair); + + assertTrue(strcmp(expectedName, parcBuffer_Overlay(actualName, 0)) == 0, + "Expected name %s, actual %s", expectedName, (char *) parcBuffer_ToString(actualName)); + + assertTrue(expectedValue == parcJSONValue_GetInteger(actualValue), + "Expected %" PRIi64 "d actual %" PRIi64 "d", expectedValue, parcJSONValue_GetInteger(actualValue)); + + parcJSON_Release(&json); +} + +LONGBOW_TEST_CASE(JSON, parcJSON_AddBoolean) +{ + PARCJSON *json = parcJSON_Create(); + + char *expectedName = "boolean"; + bool expectedValue = true; + + parcJSON_AddBoolean(json, expectedName, expectedValue); + + const PARCJSONPair *pair = parcJSON_GetPairByName(json, expectedName); + + PARCBuffer *actualName = parcJSONPair_GetName(pair); + PARCJSONValue *actualValue = parcJSONPair_GetValue(pair); + + assertTrue(strcmp(expectedName, parcBuffer_Overlay(actualName, 0)) == 0, + "Expected name %s, actual %s", expectedName, (char *) parcBuffer_ToString(actualName)); + + assertTrue(expectedValue == parcJSONValue_GetBoolean(actualValue), + "Expected %d actual %d", expectedValue, parcJSONValue_GetBoolean(actualValue)); + + parcJSON_Release(&json); +} + +LONGBOW_TEST_CASE(JSON, parcJSON_AddArray) +{ + PARCJSON *json = parcJSON_Create(); + + char *expectedName = "array"; + + PARCJSONArray *array = parcJSONArray_Create(); + PARCJSONValue *value = parcJSONValue_CreateFromCString("Some Pig"); + parcJSONArray_AddValue(array, value); + + parcJSON_AddArray(json, expectedName, array); + parcJSONArray_Release(&array); + + const PARCJSONPair *pair = parcJSON_GetPairByName(json, expectedName); + + PARCBuffer *actualName = parcJSONPair_GetName(pair); + PARCJSONValue *actualValue = parcJSONPair_GetValue(pair); + assertTrue(strcmp(expectedName, parcBuffer_Overlay(actualName, 0)) == 0, + "Expected name %s, actual %s", expectedName, (char *) parcBuffer_ToString(actualName)); + assertTrue(parcJSONValue_IsArray(actualValue), "Expect value to be type PARCJSONArray"); + array = parcJSONValue_GetArray(actualValue); + PARCJSONValue *result = parcJSONArray_GetValue(array, 0); + assertTrue(parcBuffer_Equals(parcJSONValue_GetString(result), parcJSONValue_GetString(value)), + "Expected %s actual %s", + parcJSONValue_ToString(value), + parcJSONValue_ToString(result)); + + parcJSONValue_Release(&value); + + parcJSON_Release(&json); +} + +LONGBOW_TEST_CASE(JSON, parcJSON_AddValue) +{ + PARCJSON *json = parcJSON_Create(); + + char *expectedName = "value"; + + PARCJSONValue *value = parcJSONValue_CreateFromCString("Some Pig"); + + parcJSON_AddValue(json, expectedName, value); + + const PARCJSONPair *pair = parcJSON_GetPairByName(json, expectedName); + + PARCBuffer *actualName = parcJSONPair_GetName(pair); + PARCJSONValue *actualValue = parcJSONPair_GetValue(pair); + assertTrue(strcmp(expectedName, parcBuffer_Overlay(actualName, 0)) == 0, + "Expected name %s, actual %s", expectedName, (char *) parcBuffer_ToString(actualName)); + assertTrue(parcJSONValue_IsString(actualValue), "Expect value to be type PARCJSONArray"); + assertTrue(parcBuffer_Equals(parcJSONValue_GetString(actualValue), parcJSONValue_GetString(value)), + "Expected %s actual %s", + parcJSONValue_ToString(value), + parcJSONValue_ToString(actualValue)); + + parcJSONValue_Release(&value); + + parcJSON_Release(&json); +} + +LONGBOW_TEST_FIXTURE(Static) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_JSON); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_JSONArray.c b/libparc/parc/algol/test/test_parc_JSONArray.c new file mode 100755 index 00000000..d0ad9ec5 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_JSONArray.c @@ -0,0 +1,227 @@ +/* + * 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 "../parc_JSONArray.c" + +#include <LongBow/unit-test.h> +#include <stdio.h> + +#include "../parc_List.h" +#include "../parc_ArrayList.h" +#include "../parc_SafeMemory.h" +#include "../parc_Memory.h" +#include <parc/testing/parc_ObjectTesting.h> + +LONGBOW_TEST_RUNNER(parc_JSONArray) +{ + // 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(Static); + LONGBOW_RUN_TEST_FIXTURE(parc_JSONArray); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_JSONArray) +{ + 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(parc_JSONArray) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(parc_JSONArray) +{ + LONGBOW_RUN_TEST_CASE(parc_JSONArray, parcJSONArray_CreateRelease); + LONGBOW_RUN_TEST_CASE(parc_JSONArray, parcJSONArray_Equals); + LONGBOW_RUN_TEST_CASE(parc_JSONArray, parcJSONArray_AddValue); + LONGBOW_RUN_TEST_CASE(parc_JSONArray, parcJSONArray_GetLength); + LONGBOW_RUN_TEST_CASE(parc_JSONArray, parcJSONArray_GetValue); + LONGBOW_RUN_TEST_CASE(parc_JSONArray, parcJSONArray_BuildString); + LONGBOW_RUN_TEST_CASE(parc_JSONArray, parcJSONArray_ToString); + LONGBOW_RUN_TEST_CASE(parc_JSONArray, parcJSONArray_Display); +} + +LONGBOW_TEST_FIXTURE_SETUP(parc_JSONArray) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(parc_JSONArray) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + if (outstandingAllocations != 0) { + printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(parc_JSONArray, parcJSONArray_CreateRelease) +{ + PARCJSONArray *expected = parcJSONArray_Create(); + parcJSONArray_AssertValid(expected); + assertNotNull(expected, "Expected non-null return value from parcJSONArray_Create"); + + PARCJSONArray *actual = parcJSONArray_Acquire(expected); + parcJSONArray_AssertValid(actual); + + parcJSONArray_Release(&actual); + assertNull(actual, "Expected null value set by parcJSONArray_Release"); + parcJSONArray_AssertValid(expected); + + parcJSONArray_Release(&expected); + assertNull(expected, "Expected null value set by parcJSONArray_Release"); +} + +LONGBOW_TEST_CASE(parc_JSONArray, parcJSONArray_Equals) +{ + PARCJSONArray *x = parcJSONArray_Create(); + PARCJSONArray *y = parcJSONArray_Create(); + PARCJSONArray *z = parcJSONArray_Create(); + + PARCJSONArray *notEqual1 = parcJSONArray_Create(); + PARCJSONValue *value = parcJSONValue_CreateFromCString("Hello"); + parcJSONArray_AddValue(notEqual1, value); + parcJSONValue_Release(&value); + + parcObjectTesting_AssertEqualsFunction(parcJSONArray_Equals, x, y, z, notEqual1); + + parcJSONArray_Release(&x); + parcJSONArray_Release(&y); + parcJSONArray_Release(&z); + parcJSONArray_Release(¬Equal1); +} + +LONGBOW_TEST_CASE(parc_JSONArray, parcJSONArray_AddValue) +{ + PARCJSONArray *expected = parcJSONArray_Create(); + PARCJSONValue *value = parcJSONValue_CreateFromInteger(10); + parcJSONArray_AddValue(expected, value); + parcJSONValue_Release(&value); + + parcJSONArray_Release(&expected); +} + +LONGBOW_TEST_CASE(parc_JSONArray, parcJSONArray_GetLength) +{ + PARCJSONArray *expected = parcJSONArray_Create(); + PARCJSONValue *value = parcJSONValue_CreateFromInteger(10); + parcJSONArray_AddValue(expected, value); + parcJSONValue_Release(&value); + assertTrue(parcJSONArray_GetLength(expected) == 1, "Expected a length of 1"); + + parcJSONArray_Release(&expected); +} + +LONGBOW_TEST_CASE(parc_JSONArray, parcJSONArray_GetValue) +{ + PARCJSONArray *array = parcJSONArray_Create(); + PARCJSONValue *expected = parcJSONValue_CreateFromInteger(10); + parcJSONArray_AddValue(array, expected); + + PARCJSONValue *actual = parcJSONArray_GetValue(array, 0); + + assertTrue(expected == actual, "Expected different value"); + + parcJSONValue_Release(&expected); + parcJSONArray_Release(&array); +} + +LONGBOW_TEST_CASE(parc_JSONArray, parcJSONArray_BuildString) +{ + PARCJSONArray *array = parcJSONArray_Create(); + PARCJSONValue *expected = parcJSONValue_CreateFromInteger(10); + parcJSONArray_AddValue(array, expected); + + PARCBufferComposer *composer = parcBufferComposer_Create(); + parcJSONArray_BuildString(array, composer, false); + + PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); + parcBufferComposer_Release(&composer); + char *result = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + + assertTrue(strlen(result) > 0, "Expected non-empty string result"); + + parcMemory_Deallocate((void **) &result); + + composer = parcBufferComposer_Create(); + parcJSONArray_BuildString(array, composer, true); + tempBuffer = parcBufferComposer_ProduceBuffer(composer); + parcBufferComposer_Release(&composer); + result = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + + assertTrue(strlen(result) > 0, "Expected non-empty string result"); + + parcMemory_Deallocate((void **) &result); + + parcJSONValue_Release(&expected); + parcJSONArray_Release(&array); +} + +LONGBOW_TEST_CASE(parc_JSONArray, parcJSONArray_ToString) +{ + PARCJSONArray *array = parcJSONArray_Create(); + PARCJSONValue *expected = parcJSONValue_CreateFromInteger(10); + parcJSONArray_AddValue(array, expected); + parcJSONValue_Release(&expected); + + const char *string = parcJSONArray_ToString(array); + + parcMemory_Deallocate((void **) &string); + + parcJSONArray_Release(&array); +} + +LONGBOW_TEST_CASE(parc_JSONArray, parcJSONArray_Display) +{ + PARCJSONArray *array = parcJSONArray_Create(); + PARCJSONValue *expected = parcJSONValue_CreateFromInteger(10); + parcJSONArray_AddValue(array, expected); + parcJSONValue_Release(&expected); + + parcJSONArray_Display(array, 0); + + parcJSONArray_Release(&array); +} + +LONGBOW_TEST_FIXTURE(Static) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_JSONArray); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_JSONPair.c b/libparc/parc/algol/test/test_parc_JSONPair.c new file mode 100644 index 00000000..b8c0c3f9 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_JSONPair.c @@ -0,0 +1,421 @@ +/* + * 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 "../parc_JSONPair.c" +#include <LongBow/unit-test.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. + +#include <stdio.h> +#include <fcntl.h> +#include <inttypes.h> + +#include "../parc_List.h" +#include "../parc_ArrayList.h" +#include "../parc_SafeMemory.h" +#include "../parc_Memory.h" +#include <parc/testing/parc_ObjectTesting.h> + +LONGBOW_TEST_RUNNER(parc_JSONPair) +{ + // 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(Static); + LONGBOW_RUN_TEST_FIXTURE(JSONPair); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_JSONPair) +{ + 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(parc_JSONPair) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(JSONPair) +{ + LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateAcquireRelease); + LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_BuildString); + LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_ToString); + LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_Display); + LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_Equals); + LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_Parser); + + LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateNULL); + LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateValue); + LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateString); + LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateFromBoolean); + LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateFromInteger); + LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateFromFloat); + LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateFromJSONArray); + LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateFromJSON); +} + +LONGBOW_TEST_FIXTURE_SETUP(JSONPair) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(JSONPair) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + if (outstandingAllocations != 0) { + printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateAcquireRelease) +{ + PARCBuffer *name = parcBuffer_WrapCString("name"); + + PARCBuffer *stringValue = parcBuffer_WrapCString("foo"); + PARCJSONValue *value = parcJSONValue_CreateFromString(stringValue); + parcBuffer_Release(&stringValue); + + PARCJSONPair *pair = parcJSONPair_Create(name, value); + + assertTrue(parcBuffer_Equals(name, pair->name), + "Expected '%s' actual '%s'", parcBuffer_ToString(name), parcBuffer_ToString(pair->name)); + assertTrue(value == pair->value, + "Expected %p' actual %p", (void *) value, (void *) pair->value); + + PARCJSONPair *reference = parcJSONPair_Acquire(pair); + + assertTrue(reference == pair, + "Expected parcJSONPair_Acquire to return the same pointer as the original."); + + parcBuffer_Release(&name); + parcJSONValue_Release(&value); + parcJSONPair_Release(&reference); + parcJSONPair_Release(&pair); +} + +LONGBOW_TEST_CASE(JSONPair, parcJSONPair_Display) +{ + PARCBuffer *name = parcBuffer_WrapCString("name"); + PARCBuffer *value = parcBuffer_WrapCString("foo"); + + PARCJSONValue *jsonValue = parcJSONValue_CreateFromString(value); + parcBuffer_Release(&value); + PARCJSONPair *pair = parcJSONPair_Create(name, jsonValue); + parcBuffer_Release(&name); + parcJSONValue_Release(&jsonValue); + + parcJSONPair_Display(pair, 0); + + parcJSONPair_Release(&pair); +} + +LONGBOW_TEST_CASE(JSONPair, parcJSONPair_BuildString) +{ + PARCBuffer *name = parcBuffer_WrapCString("name"); + PARCBuffer *value = parcBuffer_WrapCString("foo/bar"); + + PARCJSONValue *jsonValue = parcJSONValue_CreateFromString(value); + parcBuffer_Release(&value); + PARCJSONPair *pair = parcJSONPair_Create(name, jsonValue); + parcBuffer_Release(&name); + parcJSONValue_Release(&jsonValue); + + // umcompressed + PARCBufferComposer *composer = parcBufferComposer_Create(); + parcJSONPair_BuildString(pair, composer, false); + PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); + char *actual = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + parcBufferComposer_Release(&composer); + + char *expected = "\"name\" : \"foo\\/bar\""; + assertTrue(strcmp(expected, actual) == 0, + "Expected '%s' actual '%s'", expected, actual); + parcMemory_Deallocate((void **) &actual); + + // compressed + composer = parcBufferComposer_Create(); + parcJSONPair_BuildString(pair, composer, true); + tempBuffer = parcBufferComposer_ProduceBuffer(composer); + actual = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + parcBufferComposer_Release(&composer); + + expected = "\"name\":\"foo/bar\""; + assertTrue(strcmp(expected, actual) == 0, + "Expected '%s' actual '%s'", expected, actual); + parcMemory_Deallocate((void **) &actual); + + parcJSONPair_Release(&pair); +} + +LONGBOW_TEST_CASE(JSONPair, parcJSONPair_ToString) +{ + PARCBuffer *name = parcBuffer_WrapCString("name"); + PARCBuffer *value = parcBuffer_WrapCString("foo"); + + PARCJSONValue *jsonValue = parcJSONValue_CreateFromString(value); + parcBuffer_Release(&value); + PARCJSONPair *pair = parcJSONPair_Create(name, jsonValue); + parcBuffer_Release(&name); + parcJSONValue_Release(&jsonValue); + + char *expected = "\"name\" : \"foo\""; + char *actual = parcJSONPair_ToString(pair); + + assertTrue(strcmp(expected, actual) == 0, + "Expected '%s' actual '%s'", expected, actual); + parcMemory_Deallocate((void **) &actual); + + parcJSONPair_Release(&pair); +} + +LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateNULL) +{ + char *name = "MyNull"; + PARCBuffer *expectedName = parcBuffer_AllocateCString(name); + + PARCJSONPair *pair = parcJSONPair_CreateFromNULL(name); + + assertTrue(parcBuffer_Equals(expectedName, parcJSONPair_GetName(pair)), + "Expected name '%s', got '%s'", name, parcBuffer_ToString(parcJSONPair_GetName(pair))); + + assertTrue(parcJSONValue_IsNull(parcJSONPair_GetValue(pair)), + "Expected a JSON Null value."); + + parcJSONPair_Release(&pair); + parcBuffer_Release(&expectedName); +} + +LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateValue) +{ + char *name = "MyNull"; + PARCBuffer *expectedName = parcBuffer_AllocateCString(name); + PARCJSONValue *value = parcJSONValue_CreateFromCString("Some Pig"); + + PARCJSONPair *pair = parcJSONPair_CreateFromJSONValue(name, value); + + assertTrue(parcBuffer_Equals(expectedName, parcJSONPair_GetName(pair)), + "Expected name '%s', got '%s'", name, parcBuffer_ToString(parcJSONPair_GetName(pair))); + + assertTrue(parcJSONValue_IsString(parcJSONPair_GetValue(pair)), + "Expected a String value."); + + assertTrue(parcJSONPair_GetValue(pair) == value, "Expect values to be equal"); + + parcJSONValue_Release(&value); + parcJSONPair_Release(&pair); + parcBuffer_Release(&expectedName); +} + +LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateString) +{ + char *name = "MyNull"; + char *value = "value"; + PARCBuffer *expectedName = parcBuffer_AllocateCString(name); + PARCJSONValue *expectedValue = parcJSONValue_CreateFromCString(value); + + PARCJSONPair *pair = parcJSONPair_CreateFromString(name, value); + + assertTrue(parcBuffer_Equals(expectedName, parcJSONPair_GetName(pair)), + "Expected name '%s', got '%s'", name, parcBuffer_ToString(parcJSONPair_GetName(pair))); + assertTrue(parcJSONValue_Equals(expectedValue, parcJSONPair_GetValue(pair)), + "Expected value '%s', Got '%s'", value, parcBuffer_ToString(parcJSONValue_GetString(parcJSONPair_GetValue(pair)))); + assertTrue(parcJSONValue_IsString(parcJSONPair_GetValue(pair)), + "Expected a JSON String value."); + + parcJSONPair_Release(&pair); + parcBuffer_Release(&expectedName); + parcJSONValue_Release(&expectedValue); +} + +LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateFromBoolean) +{ + char *name = "MyNull"; + bool value = true; + PARCBuffer *expectedName = parcBuffer_AllocateCString(name); + PARCJSONValue *expectedValue = parcJSONValue_CreateFromBoolean(value); + + PARCJSONPair *pair = parcJSONPair_CreateFromBoolean(name, value); + + assertTrue(parcBuffer_Equals(expectedName, parcJSONPair_GetName(pair)), + "Expected name '%s', got '%s'", name, parcBuffer_ToString(parcJSONPair_GetName(pair))); + assertTrue(parcJSONValue_Equals(expectedValue, parcJSONPair_GetValue(pair)), + "Expected value '%d', Got '%d'", value, parcJSONValue_GetBoolean(parcJSONPair_GetValue(pair))); + + assertTrue(parcJSONValue_IsBoolean(parcJSONPair_GetValue(pair)), + "Expected a JSON Boolean value."); + + parcJSONPair_Release(&pair); + parcBuffer_Release(&expectedName); + parcJSONValue_Release(&expectedValue); +} + +LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateFromInteger) +{ + char *name = "MyNull"; + int value = 31415; + PARCBuffer *expectedName = parcBuffer_AllocateCString(name); + PARCJSONValue *expectedValue = parcJSONValue_CreateFromInteger(value); + + PARCJSONPair *pair = parcJSONPair_CreateFromInteger(name, value); + + assertTrue(parcBuffer_Equals(expectedName, parcJSONPair_GetName(pair)), + "Expected name '%s', got '%s'", name, parcBuffer_ToString(parcJSONPair_GetName(pair))); + assertTrue(parcJSONValue_Equals(expectedValue, parcJSONPair_GetValue(pair)), + "Expected value '%d', Got '%" PRIi64 "'", value, parcJSONValue_GetInteger(parcJSONPair_GetValue(pair))); + + assertTrue(parcJSONValue_IsNumber(parcJSONPair_GetValue(pair)), + "Expected a JSON Integer value."); + + parcJSONPair_Release(&pair); + parcBuffer_Release(&expectedName); + parcJSONValue_Release(&expectedValue); +} + +LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateFromFloat) +{ + char *name = "MyNull"; + double value = 3.1; + PARCBuffer *expectedName = parcBuffer_AllocateCString(name); + PARCJSONValue *expectedValue = parcJSONValue_CreateFromFloat(value); + + PARCJSONPair *pair = parcJSONPair_CreateFromDouble(name, value); + + assertTrue(parcBuffer_Equals(expectedName, parcJSONPair_GetName(pair)), + "Expected name '%s', got '%s'", name, parcBuffer_ToString(parcJSONPair_GetName(pair))); + assertTrue(parcJSONValue_Equals(expectedValue, parcJSONPair_GetValue(pair)), + "Expected %g, got %Lg", value, parcJSONValue_GetFloat(parcJSONPair_GetValue(pair))); + + assertTrue(parcJSONValue_IsNumber(parcJSONPair_GetValue(pair)), + "Expected a JSON number value."); + + parcJSONPair_Release(&pair); + parcBuffer_Release(&expectedName); + parcJSONValue_Release(&expectedValue); +} + +LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateFromJSONArray) +{ + char *name = "MyNull"; + PARCJSONArray *array = parcJSONArray_Create(); + + PARCBuffer *expectedName = parcBuffer_AllocateCString(name); + PARCJSONValue *expectedValue = parcJSONValue_CreateFromJSONArray(array); + + PARCJSONPair *pair = parcJSONPair_CreateFromJSONArray(name, array); + parcJSONArray_Release(&array); + + assertTrue(parcBuffer_Equals(expectedName, parcJSONPair_GetName(pair)), + "Expected name '%s', got '%s'", name, parcBuffer_ToString(parcJSONPair_GetName(pair))); + assertTrue(parcJSONValue_Equals(expectedValue, parcJSONPair_GetValue(pair)), + "Expected the value to be equal the same array provided"); + + assertTrue(parcJSONValue_IsArray(parcJSONPair_GetValue(pair)), + "Expected a JSON Array value."); + + parcJSONPair_Release(&pair); + parcBuffer_Release(&expectedName); + parcJSONValue_Release(&expectedValue); +} + +LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateFromJSON) +{ + char *name = "MyNull"; + PARCJSON *value = parcJSON_Create(); + + PARCBuffer *expectedName = parcBuffer_AllocateCString(name); + PARCJSONValue *expectedValue = parcJSONValue_CreateFromJSON(value); + + PARCJSONPair *pair = parcJSONPair_CreateFromJSON(name, value); + + assertTrue(parcBuffer_Equals(expectedName, parcJSONPair_GetName(pair)), + "Expected name '%s', got '%s'", name, parcBuffer_ToString(parcJSONPair_GetName(pair))); + assertTrue(parcJSONValue_Equals(expectedValue, parcJSONPair_GetValue(pair)), + "Expected %s", parcJSON_ToString(value)); + + assertTrue(parcJSONValue_IsJSON(parcJSONPair_GetValue(pair)), + "Expected a JSON Object value."); + + parcJSONPair_Release(&pair); + parcBuffer_Release(&expectedName); + parcJSONValue_Release(&expectedValue); + parcJSON_Release(&value); +} + +LONGBOW_TEST_CASE(JSONPair, parcJSONPair_Equals) +{ + char *name = "MyNull"; + char *unequalName = "foo"; + int value = 31415; + int unequalValue = 141; + + PARCJSONPair *pair = parcJSONPair_CreateFromInteger(name, value); + PARCJSONPair *y = parcJSONPair_CreateFromInteger(name, value); + PARCJSONPair *z = parcJSONPair_CreateFromInteger(name, value); + PARCJSONPair *unequal1 = parcJSONPair_CreateFromInteger(name, unequalValue); + PARCJSONPair *unequal2 = parcJSONPair_CreateFromInteger(unequalName, unequalValue); + + parcObjectTesting_AssertEqualsFunction(parcJSONPair_Equals, pair, y, z, unequal1, unequal2); + + parcJSONPair_Release(&pair); + parcJSONPair_Release(&y); + parcJSONPair_Release(&z); + parcJSONPair_Release(&unequal1); + parcJSONPair_Release(&unequal2); +} + +LONGBOW_TEST_CASE(JSONPair, parcJSONPair_Parser) +{ + PARCBuffer *buffer = parcBuffer_AllocateCString("\"name\" : \"value\""); + + PARCJSONParser *parser = parcJSONParser_Create(buffer); + PARCJSONPair *pair = parcJSONPair_Parser(parser); + + assertTrue(parcBuffer_Position(parcJSONPair_GetName(pair)) == 0, "Expected the JSONPair name buffer to be 'reset'"); + + parcJSONPair_Release(&pair); + parcJSONParser_Release(&parser); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_FIXTURE(Static) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_JSONPair); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_JSONParser.c b/libparc/parc/algol/test/test_parc_JSONParser.c new file mode 100755 index 00000000..63bcea8d --- /dev/null +++ b/libparc/parc/algol/test/test_parc_JSONParser.c @@ -0,0 +1,310 @@ +/* + * 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 <LongBow/unit-test.h> + +#include <stdio.h> +#include <fcntl.h> +#include <math.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. + +#include "../parc_JSONParser.c" + +#include <parc/algol/parc_JSONValue.h> + +#include <parc/algol/parc_List.h> +#include <parc/algol/parc_ArrayList.h> +#include <parc/algol/parc_SafeMemory.h> +#include <parc/algol/parc_StdlibMemory.h> +#include <parc/algol/parc_Memory.h> + +LONGBOW_TEST_RUNNER(parc_JSONParser) +{ + // 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(Static); + LONGBOW_RUN_TEST_FIXTURE(JSONParse_CreateAcquireRelease); + LONGBOW_RUN_TEST_FIXTURE(JSONParse); +// LONGBOW_RUN_TEST_FIXTURE(Performance); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_JSONParser) +{ + 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(parc_JSONParser) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + + +LONGBOW_TEST_FIXTURE(JSONParse_CreateAcquireRelease) +{ + LONGBOW_RUN_TEST_CASE(JSONParse_CreateAcquireRelease, parcJSONParser_Create); + LONGBOW_RUN_TEST_CASE(JSONParse_CreateAcquireRelease, parcJSONParser_AcquireRelease); +} + +LONGBOW_TEST_FIXTURE_SETUP(JSONParse_CreateAcquireRelease) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(JSONParse_CreateAcquireRelease) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + if (outstandingAllocations != 0) { + printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(JSONParse_CreateAcquireRelease, parcJSONParser_Create) +{ + char *string = "\"string\""; + + PARCBuffer *buffer = parcBuffer_WrapCString(string); + + PARCJSONParser *parser = parcJSONParser_Create(buffer); + + parcJSONParser_Release(&parser); + parcBuffer_Release(&buffer); + assertNull(parser, + "Expected parcJSONParser_Release to set the reference pointer to NULL"); +} + +LONGBOW_TEST_CASE(JSONParse_CreateAcquireRelease, parcJSONParser_AcquireRelease) +{ + char *string = "\"string\""; + + PARCBuffer *buffer = parcBuffer_WrapCString(string); + + PARCJSONParser *expected = parcJSONParser_Create(buffer); + + PARCJSONParser *actual = parcJSONParser_Acquire(expected); + assertTrue(actual == expected, + "Expected the acquired reference to be the same as the original instance."); + + parcJSONParser_Release(&actual); + assertNull(actual, + "Expected parcJSONParser_Release to set the reference pointer to NULL"); + + parcJSONParser_Release(&expected); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_FIXTURE(JSONParse) +{ + LONGBOW_RUN_TEST_CASE(JSONParse, parcJSONString_Parser); + LONGBOW_RUN_TEST_CASE(JSONParse, parcJSONParser_RequireString_Fail); + LONGBOW_RUN_TEST_CASE(JSONParse, parcJSONString_Parser_Quoted); + LONGBOW_RUN_TEST_CASE(JSONParse, parcJSON_Parse); + + LONGBOW_RUN_TEST_CASE(JSONParse, parcJSON_ParseFile); + LONGBOW_RUN_TEST_CASE(JSONParse, parcJSON_ParseFileToString); +} + +LONGBOW_TEST_FIXTURE_SETUP(JSONParse) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(JSONParse) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + if (outstandingAllocations != 0) { + printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(JSONParse, parcJSONString_Parser) +{ + char *string = "\"\\\" \\\\ \\b \\f \\n \\r \\t \\/\""; + PARCBuffer *buffer = parcBuffer_WrapCString(string); + + PARCJSONParser *parser = parcJSONParser_Create(buffer); + + PARCBuffer *expected = parcBuffer_AllocateCString("\" \\ \b \f \n \r \t /"); + PARCBuffer *actual = parcJSONParser_ParseString(parser); + + assertTrue(parcBuffer_Equals(expected, actual), "Expected string"); + + parcBuffer_Release(&actual); + parcBuffer_Release(&expected); + parcJSONParser_Release(&parser); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(JSONParse, parcJSONParser_RequireString_Fail) +{ + char *string = "\"string\""; + char *requiredString = "foo"; + + PARCBuffer *buffer = parcBuffer_WrapCString(string); + + PARCJSONParser *parser = parcJSONParser_Create(buffer); + + bool actual = parcJSONParser_RequireString(parser, requiredString); + + assertFalse(actual, "Expected parcJSONParser_RequireString to fail"); + + parcJSONParser_Release(&parser); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(JSONParse, parcJSONString_Parser_Quoted) +{ + char *string = "\"str\\\"ing\""; + + PARCBuffer *buffer = parcBuffer_WrapCString(string); + + PARCJSONParser *parser = parcJSONParser_Create(buffer); + + PARCBuffer *expected = parcBuffer_WrapCString("str\"ing"); + PARCBuffer *actual = parcJSONParser_ParseString(parser); + + assertTrue(parcBuffer_Equals(expected, actual), "Expected string"); + + parcBuffer_Release(&actual); + parcBuffer_Release(&expected); + parcJSONParser_Release(&parser); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(JSONParse, parcJSON_Parse) +{ + char *expected = "{ \"string\" : \"string\", \"null\" : null, \"true\" : true, \"false\" : false, \"integer\" : 31415, \"float\" : 3.141500, \"array\" : [ null, false, true, 31415, \"string\", [ null, false, true, 31415, \"string\" ], { } ] }"; + + expected = "{ \"integer\" : 31415 }"; + + expected = "{ \"string\" : \"string\", \"null\" : null, \"true\" : true, \"false\" : false, \"integer\" : 31415, \"array\" : [ null, false, true, 31415, \"string\", [ null, false, true, 31415, \"string\" ], { \"string\" : \"string\" } ] }"; + + PARCJSON *json = parcJSON_ParseString(expected); + assertNotNull(json, "Parse error for %s", expected); + + char *actual = parcJSON_ToString(json); + + assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual); + + printf("%s\n", actual); + parcMemory_Deallocate((void **) &actual); + + parcJSON_Release(&json); +} + +LONGBOW_TEST_CASE(JSONParse, parcJSON_ParseFile) +{ + char *string = NULL; + size_t nread = longBowDebug_ReadFile("data.json", &string); + assertTrue(nread != -1, "Cannot read '%s'", "data.json"); + + PARCJSON *json = parcJSON_ParseString(string); + + assertNotNull(json, "parcJSON_ParseString failed"); + + // assertTrue(longBowDebug_WriteFile("/tmp/test_parc_JSON.json", actual, strlen(actual)) != 0, + // "Can't write file"); + + parcJSON_Release(&json); +} + +LONGBOW_TEST_CASE(JSONParse, parcJSON_ParseFileToString) +{ + char *string = NULL; + size_t nread = longBowDebug_ReadFile("data.json", &string); + assertTrue(nread != -1, "Cannot read '%s'", "data.json"); + + PARCJSON *json = parcJSON_ParseString(string); + + assertNotNull(json, "parcJSON_ParseString failed"); + + char *actual = parcJSON_ToString(json); + + // assertTrue(longBowDebug_WriteFile("/tmp/test_parc_JSON.json", actual, strlen(actual)) != 0, + // "Can't write file"); + + parcMemory_Deallocate((void **) &actual); + + parcJSON_Release(&json); +} + +LONGBOW_TEST_FIXTURE(Static) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Performance) +{ + LONGBOW_RUN_TEST_CASE(Performance, parcJSON_ParseFileToString); +} + +LONGBOW_TEST_FIXTURE_SETUP(Performance) +{ + parcMemory_SetInterface(&PARCStdlibMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Performance) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Performance, parcJSON_ParseFileToString) +{ + char *string = NULL; + size_t nread = longBowDebug_ReadFile("citylots.json", &string); + assertTrue(nread != -1, "Cannot read '%s'", "citylots.json"); + + PARCJSON *json = parcJSON_ParseString(string); + + assertNotNull(json, "parcJSON_ParseString failed"); + + char *actual = parcJSON_ToString(json); + + // assertTrue(longBowDebug_WriteFile("/tmp/test_parc_JSON.json", actual, strlen(actual)) != 0, + // "Can't write file"); + + parcMemory_Deallocate((void **) &actual); + + parcJSON_Release(&json); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_JSONParser); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_JSONValue.c b/libparc/parc/algol/test/test_parc_JSONValue.c new file mode 100644 index 00000000..804eb690 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_JSONValue.c @@ -0,0 +1,1365 @@ +/* + * 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 "../parc_JSONValue.c" +#include <LongBow/unit-test.h> + +#include <stdio.h> +#include <fcntl.h> +#include <inttypes.h> + +#include "../parc_List.h" +#include "../parc_ArrayList.h" +#include "../parc_SafeMemory.h" +#include "../parc_Memory.h" + +#include <parc/testing/parc_ObjectTesting.h> + +LONGBOW_TEST_RUNNER(parc_JSONValue) +{ + // 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(Static); + LONGBOW_RUN_TEST_FIXTURE(JSONValue_CreateAcquireRelease); + LONGBOW_RUN_TEST_FIXTURE(JSONValue); + LONGBOW_RUN_TEST_FIXTURE(JSONValueParsing); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_JSONValue) +{ + 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(parc_JSONValue) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(JSONValue_CreateAcquireRelease) +{ + LONGBOW_RUN_TEST_CASE(JSONValue_CreateAcquireRelease, _createValue); + LONGBOW_RUN_TEST_CASE(JSONValue_CreateAcquireRelease, parcJSONValue_AcquireRelease); +} + +LONGBOW_TEST_FIXTURE_SETUP(JSONValue_CreateAcquireRelease) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(JSONValue_CreateAcquireRelease) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + if (outstandingAllocations != 0) { + printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(JSONValue_CreateAcquireRelease, _createValue) +{ + PARCJSONValue *result = parcJSONValue_CreateFromNULL(); + + assertNotNull(result, "Expected non-null return value from _createValue"); + assertTrue(parcJSONValue_IsNull(result), + "Expected PARCJSONValueType_Null"); + + parcJSONValue_Release(&result); + assertNull(result, "Expected parcJSONValue_Release to NULL the instance pointer."); +} + + +LONGBOW_TEST_CASE(JSONValue_CreateAcquireRelease, parcJSONValue_AcquireRelease) +{ + PARCJSONValue *result = parcJSONValue_CreateFromNULL(); + + assertNotNull(result, "Expected non-null return value from _createValue"); + assertTrue(parcJSONValue_IsNull(result), + "Expected PARCJSONValueType_Null"); + + PARCJSONValue *actual = parcJSONValue_Acquire(result); + assertTrue(result == actual, "Expected parcJSONValue_Acquire return value to be same as the original."); + + parcJSONValue_Release(&actual); + parcJSONValue_Release(&result); + assertNull(result, "Expected parcJSONValue_Release to NULL the instance pointer."); +} + + +LONGBOW_TEST_FIXTURE(JSONValue) +{ + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_NULL); + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_Boolean); + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_Float); + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_Integer); + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_String); + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_JSON); + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_Array); + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_Timespec); + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_Timeval); + + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_IsValid); + + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Display); + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_BuildString); + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_ToString_NULL); + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_ToString_Array); + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_ToString_Boolean); + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_ToString_Float); + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_ToString_Integer); + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_ToString_String); + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_CreateCString); + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_ToString_JSON); + + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Equals_NULL); + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Equals_Boolean); + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Equals_Integer); + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Equals_Float); + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Equals_String); + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Equals_Object); + LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Equals_Array); +} + +LONGBOW_TEST_FIXTURE_SETUP(JSONValue) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(JSONValue) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + if (outstandingAllocations != 0) { + printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_IsValid) +{ + bool actual = parcJSONValue_IsValid(NULL); + assertFalse(actual, "Expected a NULL value to be invalid"); + + PARCJSONValue *value = parcJSONValue_CreateFromNULL(); + + actual = parcJSONValue_IsValid(value); + parcJSONValue_Release(&value); + assertTrue(actual, "Expected a NULL value to be invalid"); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_JSON) +{ + PARCJSON *json = parcJSON_Create(); + PARCJSONValue *value = parcJSONValue_CreateFromJSON(json); + + assertTrue(parcJSONValue_IsJSON(value), + "Expected PARCJSONValueType_JSON"); + + assertTrue(parcJSONValue_GetJSON(value) == json, + "Expected parcJSONValue_GetJSON to return the original instance pointer."); + parcJSONValue_Release(&value); + assertNull(value, "Expected NULL pointer."); + parcJSON_Release(&json); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_Timeval) +{ + struct timeval timeval = { .tv_sec = 42, .tv_usec = 23 }; + PARCJSONValue *value = parcJSONValue_CreateFromTimeval(&timeval); + + assertTrue(parcJSONValue_IsJSON(value), + "Expected PARCJSONValueType_JSON"); + + struct timeval actual; + parcJSONValue_GetTimeval(value, &actual); + assertTrue(timeval.tv_sec == actual.tv_sec, "Expected seconds to be equal."); + assertTrue(timeval.tv_usec == actual.tv_usec, "Expected seconds to be equal."); + + parcJSONValue_Release(&value); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_Timespec) +{ + struct timespec timespec = { .tv_sec = 42, .tv_nsec = 23 }; + PARCJSONValue *value = parcJSONValue_CreateFromTimespec(×pec); + + assertTrue(parcJSONValue_IsJSON(value), + "Expected PARCJSONValueType_JSON"); + + struct timespec testTS; + parcJSONValue_GetTimespec(value, &testTS); + assertTrue(memcmp(×pec, &testTS, sizeof(struct timespec)) == 0, + "Expected parcJSONValue_GetTimespec to return the original instance pointer."); + parcJSONValue_Release(&value); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_NULL) +{ + PARCJSONValue *value = parcJSONValue_CreateFromNULL(); + + assertTrue(value->type == PARCJSONValueType_Null, + "Expected PARCJSONValueType_Null, actual %d", value->type); + assertTrue(parcJSONValue_IsNull(value), + "Expected PARCJSONValueType_Null"); + parcJSONValue_Release(&value); + assertNull(value, "Expected NULL pointer."); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_Boolean) +{ + bool expected = true; + PARCJSONValue *value = parcJSONValue_CreateFromBoolean(expected); + + assertTrue(value->type == PARCJSONValueType_Boolean, + "Expected PARCJSONValueType_BooleanON_VALUE_BOOLEAN, actual %d", value->type); + assertTrue(value->value.boolean == expected, "Expected %d actual %d", expected, value->value.boolean); + + assertTrue(parcJSONValue_IsBoolean(value), + "Expected PARCJSONValueType_Boolean"); + assertTrue(parcJSONValue_GetBoolean(value), "Expected value to be true"); + parcJSONValue_Release(&value); + assertNull(value, "Expected NULL pointer."); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_Float) +{ + double expected = 3.1415; + PARCJSONValue *value = parcJSONValue_CreateFromFloat(expected); + + assertTrue(parcJSONValue_IsNumber(value), + "Expected parcJSONValue_IsNumber to be true."); + assertTrue(parcJSONValue_GetFloat(value) == expected, + "Expected %g, actual %Lg", expected, parcJSONValue_GetFloat(value)); + + char *expectedString = "3.141500"; + char *actualString = parcJSONValue_ToString(value); + assertTrue(strcmp(expectedString, actualString) == 0, "Exepcted %s, actual %s", expectedString, actualString); + parcMemory_Deallocate((void **) &actualString); + + parcJSONValue_Release(&value); + assertNull(value, "Expected NULL pointer."); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_Integer) +{ + int expected = 31415; + PARCJSONValue *value = parcJSONValue_CreateFromInteger(expected); + + assertTrue(parcJSONValue_IsNumber(value), + "Expected parcJSONValue_IsNumber"); + int64_t actual = parcJSONValue_GetInteger(value); + assertTrue(expected == actual, "Expected %d, actual %" PRIi64 "", expected, actual); + parcJSONValue_Release(&value); + assertNull(value, "Expected NULL pointer."); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_String) +{ + PARCBuffer *expected = parcBuffer_WrapCString("31415"); + PARCJSONValue *value = parcJSONValue_CreateFromString(expected); + + assertTrue(value->type == PARCJSONValueType_String, + "Expected parcJSONValueType.String, actual %d", value->type); + assertTrue(parcBuffer_Equals(value->value.string, expected), + "Expected %s actual %s", parcBuffer_ToString(expected), parcBuffer_ToString(value->value.string)); + assertTrue(parcJSONValue_IsString(value), + "Expected PARCJSONValueType_String"); + + assertTrue(parcBuffer_Equals(parcJSONValue_GetString(value), expected), "Expected value did not match actual value"); + parcJSONValue_Release(&value); + assertNull(value, "Expected NULL pointer."); + parcBuffer_Release(&expected); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_CreateCString) +{ + PARCBuffer *expected = parcBuffer_WrapCString("31415"); + + PARCJSONValue *value = parcJSONValue_CreateFromCString("31415"); + + assertTrue(value->type == PARCJSONValueType_String, + "Expected parcJSONValueType.String, actual %d", value->type); + + assertTrue(parcBuffer_Equals(parcJSONValue_GetString(value), expected), "Assert:") + { + char *expectedString = parcBuffer_ToString(expected); + char *actualString = parcBuffer_ToString(parcJSONValue_GetString(value)); + printf("Expected '%s', actual '%s'", expectedString, actualString); + parcMemory_Deallocate((void **) &expectedString); + parcMemory_Deallocate((void **) &actualString); + } + + parcJSONValue_Release(&value); + assertNull(value, "Expected NULL pointer."); + parcBuffer_Release(&expected); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_Array) +{ + PARCJSONArray *array = parcJSONArray_Create(); + + PARCJSONValue *value = parcJSONValue_CreateFromNULL(); + parcJSONArray_AddValue(array, value); + parcJSONValue_Release(&value); + + value = parcJSONValue_CreateFromJSONArray(array); + + parcJSONValue_Release(&value); + + parcJSONArray_Release(&array); + assertNull(value, "Expected NULL pointer."); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_BuildString) +{ + PARCJSONArray *array = parcJSONArray_Create(); + + PARCJSONValue *value = parcJSONValue_CreateFromNULL(); + parcJSONArray_AddValue(array, value); + parcJSONValue_Release(&value); + + value = parcJSONValue_CreateFromBoolean(false); + parcJSONArray_AddValue(array, value); + parcJSONValue_Release(&value); + + value = parcJSONValue_CreateFromBoolean(true); + parcJSONArray_AddValue(array, value); + parcJSONValue_Release(&value); + + value = parcJSONValue_CreateFromInteger(31415); + parcJSONArray_AddValue(array, value); + parcJSONValue_Release(&value); + + PARCBuffer *stringValue = parcBuffer_WrapCString("stringA/stringB"); + value = parcJSONValue_CreateFromString(stringValue); + parcJSONArray_AddValue(array, value); + parcJSONValue_Release(&value); + parcBuffer_Release(&stringValue); + + value = parcJSONValue_CreateFromJSONArray(array); + parcJSONArray_Release(&array); + + // Uncompacted + PARCBufferComposer *composer = parcBufferComposer_Create(); + parcJSONValue_BuildString(value, composer, false); + + PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); + char *actual = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + parcBufferComposer_Release(&composer); + + char *expected = "[ null, false, true, 31415, \"stringA\\/stringB\" ]"; + + assertTrue(strcmp(actual, expected) == 0, + "Expected '%s', actual '%s'", expected, actual); + + parcMemory_Deallocate((void **) &actual); + + // Compacted + composer = parcBufferComposer_Create(); + parcJSONValue_BuildString(value, composer, true); + + tempBuffer = parcBufferComposer_ProduceBuffer(composer); + actual = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + parcBufferComposer_Release(&composer); + + expected = "[null,false,true,31415,\"stringA/stringB\"]"; + + assertTrue(strcmp(actual, expected) == 0, + "Expected '%s', actual '%s'", expected, actual); + + parcMemory_Deallocate((void **) &actual); + + + parcJSONValue_Release(&value); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_ToString_Array) +{ + PARCJSONArray *array = parcJSONArray_Create(); + + PARCJSONValue *value = parcJSONValue_CreateFromNULL(); + parcJSONArray_AddValue(array, value); + parcJSONValue_Release(&value); + + value = parcJSONValue_CreateFromBoolean(false); + parcJSONArray_AddValue(array, value); + parcJSONValue_Release(&value); + + value = parcJSONValue_CreateFromBoolean(true); + parcJSONArray_AddValue(array, value); + parcJSONValue_Release(&value); + + value = parcJSONValue_CreateFromInteger(31415); + parcJSONArray_AddValue(array, value); + parcJSONValue_Release(&value); + + PARCBuffer *stringValue = parcBuffer_WrapCString("stringA/stringB"); + value = parcJSONValue_CreateFromString(stringValue); + parcJSONArray_AddValue(array, value); + parcJSONValue_Release(&value); + parcBuffer_Release(&stringValue); + + value = parcJSONValue_CreateFromJSONArray(array); + parcJSONArray_Release(&array); + + char *expected = "[ null, false, true, 31415, \"stringA\\/stringB\" ]"; + char *actual = parcJSONValue_ToString(value); + + assertTrue(strcmp(actual, expected) == 0, + "Expected '%s', actual '%s'", expected, actual); + + parcMemory_Deallocate((void **) &actual); + parcJSONValue_Release(&value); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Display) +{ + PARCJSONValue *value = parcJSONValue_CreateFromNULL(); + parcJSONValue_Display(value, 0); + parcJSONValue_Release(&value); + + value = parcJSONValue_CreateFromBoolean(true); + parcJSONValue_Display(value, 0); + parcJSONValue_Release(&value); + + value = parcJSONValue_CreateFromCString("hello"); + parcJSONValue_Display(value, 0); + parcJSONValue_Release(&value); + + value = parcJSONValue_CreateFromFloat(3.14); + parcJSONValue_Display(value, 0); + parcJSONValue_Release(&value); + + value = parcJSONValue_CreateFromInteger(314); + parcJSONValue_Display(value, 0); + parcJSONValue_Release(&value); + + PARCJSONArray *array = parcJSONArray_Create(); + value = parcJSONValue_CreateFromJSONArray(array); + parcJSONValue_Display(value, 0); + parcJSONValue_Release(&value); + parcJSONArray_Release(&array); + + PARCJSON *json = parcJSON_Create(); + value = parcJSONValue_CreateFromJSON(json); + parcJSONValue_Display(value, 0); + parcJSONValue_Release(&value); + parcJSON_Release(&json); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_ToString_NULL) +{ + char *expected = "null"; + PARCJSONValue *value = parcJSONValue_CreateFromNULL(); + + char *actual = parcJSONValue_ToString(value); + assertTrue(strcmp(actual, expected) == 0, "Expected '%s', actual '%s'", expected, actual); + + parcMemory_Deallocate((void **) &actual); + parcJSONValue_Release(&value); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_ToString_Boolean) +{ + char *expected = "true"; + PARCJSONValue *value = parcJSONValue_CreateFromBoolean(expected); + + char *actual = parcJSONValue_ToString(value); + assertTrue(strcmp(actual, expected) == 0, "Expected '%s', actual '%s'", expected, actual); + + parcMemory_Deallocate((void **) &actual); + parcJSONValue_Release(&value); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_ToString_Float) +{ + struct test_values { + char *string; + long double value; + long double error; + } successful[] = { + { "-0.0415e-12", -0.0415e-12, 0.00001e-12 }, + { "-0.0415e12", -0.0415e12, 0.00001e12 }, + { "-0.0415", -0.0415, 0.00001 }, + { "-3.0415", -3.0415, 0.00001 }, + { "123.456", 123.456, 0.0001 }, + { "123.456e78", 123.456e78, 0.0001e78 }, + { "123.456e-78", 123.456e-78, 0.0001e-78 }, + { "123.456e-78", 123.456e-78, 0.0001e-78 }, + { "4e1", 40.0, 0.0001e-78 }, + { NULL }, + }; + + for (int i = 0; successful[i].string != NULL; i++) { + PARCBuffer *buffer = parcBuffer_WrapCString(successful[i].string); + PARCJSONParser *parser = parcJSONParser_Create(buffer); + parcBuffer_Release(&buffer); + + PARCJSONValue *expected = _parcJSONValue_NumberParser(parser); + + char *string = parcJSONValue_ToString(expected); + assertTrue(strcmp(successful[i].string, string) == 0, + "Expected %s, actual %s", successful[i].string, string); + parcMemory_Deallocate((void **) &string); + + parcJSONValue_Release(&expected); + parcJSONParser_Release(&parser); + } +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_ToString_Integer) +{ + char *expected = "31415"; + PARCJSONValue *value = parcJSONValue_CreateFromInteger(31415); + + char *actual = parcJSONValue_ToString(value); + assertTrue(strcmp(actual, expected) == 0, + "Expected '%s', actual '%s'", expected, actual); + + parcMemory_Deallocate((void **) &actual); + parcJSONValue_Release(&value); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_ToString_String) +{ + char *input = "31415\b"; + char *expected = "\"31415\\b\""; + + PARCBuffer *stringValue = parcBuffer_WrapCString(input); + PARCJSONValue *value = parcJSONValue_CreateFromString(stringValue); + parcBuffer_Release(&stringValue); + + char *actual = parcJSONValue_ToString(value); + assertTrue(strcmp(actual, expected) == 0, "Expected '%s', actual '%s'", expected, actual); + + parcMemory_Deallocate((void **) &actual); + parcJSONValue_Release(&value); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_ToString_JSON) +{ + char *expected = "{ }"; + PARCJSON *json = parcJSON_Create(); + PARCJSONValue *value = parcJSONValue_CreateFromJSON(json); + parcJSON_Release(&json); + + char *actual = parcJSONValue_ToString(value); + assertTrue(strcmp(actual, expected) == 0, "Expected '%s', actual '%s'", expected, actual); + + parcMemory_Deallocate((void **) &actual); + parcJSONValue_Release(&value); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Equals_NULL) +{ + PARCJSONValue *example = parcJSONValue_CreateFromNULL(); + + PARCJSONValue *equal1 = parcJSONValue_CreateFromNULL(); + PARCJSONValue *equal2 = parcJSONValue_CreateFromNULL(); + + PARCBuffer *stringBuffer = parcBuffer_AllocateCString("Hello"); + PARCJSONValue *string = parcJSONValue_CreateFromString(stringBuffer); + parcBuffer_Release(&stringBuffer); + + parcObjectTesting_AssertEqualsFunction(parcJSONValue_Equals, example, equal1, equal2, string); + + parcJSONValue_Release(&string); + parcJSONValue_Release(&equal2); + parcJSONValue_Release(&equal1); + parcJSONValue_Release(&example); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Equals_Boolean) +{ + PARCJSONValue *example = parcJSONValue_CreateFromBoolean(true); + + PARCJSONValue *equal1 = parcJSONValue_CreateFromBoolean(true); + PARCJSONValue *equal2 = parcJSONValue_CreateFromBoolean(true); + + PARCJSONValue *unequal1 = parcJSONValue_CreateFromBoolean(false); + + PARCBuffer *stringBuffer = parcBuffer_AllocateCString("Hello"); + PARCJSONValue *string = parcJSONValue_CreateFromString(stringBuffer); + parcBuffer_Release(&stringBuffer); + + parcObjectTesting_AssertEqualsFunction(parcJSONValue_Equals, example, equal1, equal2, unequal1, string); + + parcJSONValue_Release(&string); + parcJSONValue_Release(&unequal1); + parcJSONValue_Release(&equal2); + parcJSONValue_Release(&equal1); + parcJSONValue_Release(&example); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Equals_Integer) +{ + PARCJSONValue *example = parcJSONValue_CreateFromInteger(31415); + + PARCJSONValue *equal1 = parcJSONValue_CreateFromInteger(31415); + PARCJSONValue *equal2 = parcJSONValue_CreateFromInteger(31415); + + PARCJSONValue *unequal1 = parcJSONValue_CreateFromInteger(4); + + PARCBuffer *stringBuffer = parcBuffer_AllocateCString("Hello"); + PARCJSONValue *string = parcJSONValue_CreateFromString(stringBuffer); + parcBuffer_Release(&stringBuffer); + + parcObjectTesting_AssertEqualsFunction(parcJSONValue_Equals, example, equal1, equal2, unequal1, string); + + parcJSONValue_Release(&string); + parcJSONValue_Release(&unequal1); + parcJSONValue_Release(&equal2); + parcJSONValue_Release(&equal1); + parcJSONValue_Release(&example); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Equals_Float) +{ + PARCJSONValue *example = parcJSONValue_CreateFromFloat(3.1415); + + PARCJSONValue *equal1 = parcJSONValue_CreateFromFloat(3.1415); + PARCJSONValue *equal2 = parcJSONValue_CreateFromFloat(3.1415); + + PARCJSONValue *unequal1 = parcJSONValue_CreateFromFloat(4.0); + + PARCBuffer *stringBuffer = parcBuffer_AllocateCString("Hello"); + PARCJSONValue *string = parcJSONValue_CreateFromString(stringBuffer); + parcBuffer_Release(&stringBuffer); + + parcObjectTesting_AssertEqualsFunction(parcJSONValue_Equals, example, equal1, equal2, unequal1, string); + + parcJSONValue_Release(&string); + parcJSONValue_Release(&unequal1); + parcJSONValue_Release(&equal2); + parcJSONValue_Release(&equal1); + parcJSONValue_Release(&example); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Equals_String) +{ + PARCBuffer *stringBuffer = parcBuffer_AllocateCString("Hello"); + PARCJSONValue *example = parcJSONValue_CreateFromString(stringBuffer); + parcBuffer_Release(&stringBuffer); + + stringBuffer = parcBuffer_AllocateCString("Hello"); + PARCJSONValue *equal1 = parcJSONValue_CreateFromString(stringBuffer); + parcBuffer_Release(&stringBuffer); + + stringBuffer = parcBuffer_AllocateCString("Hello"); + PARCJSONValue *equal2 = parcJSONValue_CreateFromString(stringBuffer); + parcBuffer_Release(&stringBuffer); + + PARCJSONValue *unequal1 = parcJSONValue_CreateFromFloat(4.0); + + stringBuffer = parcBuffer_AllocateCString("World"); + PARCJSONValue *string = parcJSONValue_CreateFromString(stringBuffer); + parcBuffer_Release(&stringBuffer); + + parcObjectTesting_AssertEqualsFunction(parcJSONValue_Equals, example, equal1, equal2, unequal1, string); + + parcJSONValue_Release(&string); + parcJSONValue_Release(&unequal1); + parcJSONValue_Release(&equal2); + parcJSONValue_Release(&equal1); + parcJSONValue_Release(&example); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Equals_Object) +{ + char *string = "{ \"name\" : 1, \"name2\" : 2 }"; + + PARCBuffer *buffer = parcBuffer_WrapCString(string); + PARCJSONParser *parser = parcJSONParser_Create(buffer); + parcBuffer_Release(&buffer); + + PARCJSONValue *x = parcJSONValue_ObjectParser(parser); + parcJSONParser_Release(&parser); + + assertTrue(parcJSONValue_IsJSON(x), "Expected a JSON Object value."); + + buffer = parcBuffer_WrapCString(string); + parser = parcJSONParser_Create(buffer); + parcBuffer_Release(&buffer); + + PARCJSONValue *y = parcJSONValue_ObjectParser(parser); + parcJSONParser_Release(&parser); + + buffer = parcBuffer_WrapCString(string); + parser = parcJSONParser_Create(buffer); + parcBuffer_Release(&buffer); + + PARCJSONValue *z = parcJSONValue_ObjectParser(parser); + parcJSONParser_Release(&parser); + + PARCJSONValue *unequal1 = parcJSONValue_CreateFromFloat(4.0); + + PARCJSON *json = parcJSON_Create(); + PARCJSONValue *unequal2 = parcJSONValue_CreateFromJSON(json); + parcJSON_Release(&json); + + parcObjectTesting_AssertEqualsFunction(parcJSONValue_Equals, x, y, z, unequal1, unequal2); + + parcJSONValue_Release(&x); + parcJSONValue_Release(&y); + parcJSONValue_Release(&z); + parcJSONValue_Release(&unequal1); + parcJSONValue_Release(&unequal2); +} + +LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Equals_Array) +{ + char *string = "[ \"name\", 1, true, false, null, [ ], { } ]"; + + PARCBuffer *buffer = parcBuffer_WrapCString(string); + PARCJSONParser *parser = parcJSONParser_Create(buffer); + parcBuffer_Release(&buffer); + + PARCJSONValue *x = _parcJSONValue_ArrayParser(parser); + parcJSONParser_Release(&parser); + + assertTrue(parcJSONValue_IsArray(x), "Expected a JSON Array value."); + + buffer = parcBuffer_WrapCString(string); + parser = parcJSONParser_Create(buffer); + parcBuffer_Release(&buffer); + + PARCJSONValue *y = _parcJSONValue_ArrayParser(parser); + parcJSONParser_Release(&parser); + + buffer = parcBuffer_WrapCString(string); + parser = parcJSONParser_Create(buffer); + parcBuffer_Release(&buffer); + + PARCJSONValue *z = _parcJSONValue_ArrayParser(parser); + parcJSONParser_Release(&parser); + + PARCJSONValue *unequal1 = parcJSONValue_CreateFromFloat(4.0); + + PARCJSONArray *array = parcJSONArray_Create(); + PARCJSONValue *unequal2 = parcJSONValue_CreateFromJSONArray(array); + parcJSONArray_Release(&array); + + parcObjectTesting_AssertEqualsFunction(parcJSONValue_Equals, x, y, z, unequal1, unequal2); + + parcJSONValue_Release(&x); + parcJSONValue_Release(&y); + parcJSONValue_Release(&z); + parcJSONValue_Release(&unequal1); + parcJSONValue_Release(&unequal2); +} + +LONGBOW_TEST_FIXTURE(JSONValueParsing) +{ + LONGBOW_RUN_TEST_CASE(JSONValueParsing, _parcJSONValue_NullParser); + LONGBOW_RUN_TEST_CASE(JSONValueParsing, _parcJSONValue_NullParser_Bad); + LONGBOW_RUN_TEST_CASE(JSONValueParsing, _parcJSONValue_TrueParser); + LONGBOW_RUN_TEST_CASE(JSONValueParsing, _parcJSONValue_TrueParser_Bad); + LONGBOW_RUN_TEST_CASE(JSONValueParsing, _parcJSONValue_FalseParser); + LONGBOW_RUN_TEST_CASE(JSONValueParsing, _parcJSONValue_FalseParser_Bad); + LONGBOW_RUN_TEST_CASE(JSONValueParsing, _parcJSONValue_StringParser); + LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_ObjectParser); + LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_ObjectParser_Bad_Pair); + LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_ObjectParser_Bad_Pair2); + LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_ArrayParser); + LONGBOW_RUN_TEST_CASE(JSONValueParsing, _parcJSONValue_StringParser_BAD); + + LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_NumberParser_BatchedFloat); + + LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_Comma); + LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_CloseBracket); + LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_Null); + LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_True); + LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_False); + LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_String); + LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_Array); + LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_Object); +} + +LONGBOW_TEST_FIXTURE_SETUP(JSONValueParsing) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(JSONValueParsing) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + if (outstandingAllocations != 0) { + printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(JSONValueParsing, _parcJSONValue_NullParser) +{ + char *string = "null"; + PARCBuffer *buffer = parcBuffer_WrapCString(string); + + PARCJSONParser *parser = parcJSONParser_Create(buffer); + PARCJSONValue *actual = _parcJSONValue_NullParser(parser); + + assertTrue(parcJSONValue_IsNull(actual), "Expected a JSON Null value."); + + parcJSONValue_Release(&actual); + parcJSONParser_Release(&parser); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(JSONValueParsing, _parcJSONValue_NullParser_Bad) +{ + char *string = "nulx"; + PARCBuffer *buffer = parcBuffer_WrapCString(string); + + PARCJSONParser *parser = parcJSONParser_Create(buffer); + PARCJSONValue *actual = _parcJSONValue_NullParser(parser); + + assertNull(actual, "Expected a NULL return value"); + + parcJSONParser_Release(&parser); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(JSONValueParsing, _parcJSONValue_TrueParser) +{ + char *string = "true"; + PARCBuffer *buffer = parcBuffer_WrapCString(string); + + PARCJSONParser *parser = parcJSONParser_Create(buffer); + PARCJSONValue *actual = _parcJSONValue_TrueParser(parser); + + assertTrue(parcJSONValue_IsBoolean(actual), "Expected a JSON Boolean value."); + assertTrue(parcJSONValue_GetBoolean(actual), "Expected true."); + + parcJSONValue_Release(&actual); + parcJSONParser_Release(&parser); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(JSONValueParsing, _parcJSONValue_TrueParser_Bad) +{ + char *string = "trux"; + PARCBuffer *buffer = parcBuffer_WrapCString(string); + + PARCJSONParser *parser = parcJSONParser_Create(buffer); + PARCJSONValue *actual = _parcJSONValue_TrueParser(parser); + + assertNull(actual, "Expected a NULL return value"); + + parcJSONParser_Release(&parser); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(JSONValueParsing, _parcJSONValue_FalseParser) +{ + char *string = "false"; + PARCBuffer *buffer = parcBuffer_WrapCString(string); + + PARCJSONParser *parser = parcJSONParser_Create(buffer); + PARCJSONValue *actual = _parcJSONValue_FalseParser(parser); + + assertTrue(parcJSONValue_IsBoolean(actual), "Expected a JSON Boolean value."); + assertFalse(parcJSONValue_GetBoolean(actual), "Expected false."); + + parcJSONValue_Release(&actual); + parcJSONParser_Release(&parser); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(JSONValueParsing, _parcJSONValue_FalseParser_Bad) +{ + char *string = "falsx"; + PARCBuffer *buffer = parcBuffer_WrapCString(string); + + PARCJSONParser *parser = parcJSONParser_Create(buffer); + PARCJSONValue *actual = _parcJSONValue_FalseParser(parser); + + assertNull(actual, "Expected a NULL return value"); + + parcJSONParser_Release(&parser); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(JSONValueParsing, _parcJSONValue_StringParser) +{ + char *parserInput = "\"\\\" \\\\ \\b \\f \\n \\r \\t \\/\""; + PARCBuffer *buffer = parcBuffer_WrapCString(parserInput); + PARCBuffer *expected = parcBuffer_AllocateCString("\" \\ \b \f \n \r \t /"); + + PARCJSONParser *parser = parcJSONParser_Create(buffer); + PARCJSONValue *actual = _parcJSONValue_StringParser(parser); + + assertTrue(parcJSONValue_IsString(actual), + "Expected a JSON String value."); + + assertTrue(parcBuffer_Equals(expected, actual->value.string), + "Expected '%s' actual '%s'", parcBuffer_ToString(expected), parcBuffer_ToString(actual->value.string)) + { + parcBuffer_Display(expected, 0); + parcBuffer_Display(actual->value.string, 0); + } + + char *string = parcJSONValue_ToString(actual); + assertTrue(strcmp(parserInput, string) == 0, + "Expected %s, actual %s", parserInput, string); + + parcMemory_Deallocate((void **) &string); + + parcJSONValue_Release(&actual); + parcJSONParser_Release(&parser); + parcBuffer_Release(&expected); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(JSONValueParsing, _parcJSONValue_StringParser_BAD) +{ + char *bad[] = { + "\"\t\"", + "\"", + NULL + }; + + for (int i = 0; bad[i] != NULL; i++) { + char *parserInput = bad[i]; + PARCBuffer *buffer = parcBuffer_WrapCString(parserInput); + PARCJSONParser *parser = parcJSONParser_Create(buffer); + PARCJSONValue *actual = _parcJSONValue_StringParser(parser); + + assertNull(actual, "Expected failure"); + parcBuffer_Release(&buffer); + parcJSONParser_Release(&parser); + } +} + +LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_ObjectParser) +{ + char *string = "{ \"name\" : 1, \"name2\" : 2 }"; + PARCBuffer *buffer = parcBuffer_WrapCString(string); + + PARCJSONParser *parser = parcJSONParser_Create(buffer); + PARCJSONValue *actual = parcJSONValue_ObjectParser(parser); + + assertTrue(parcJSONValue_IsJSON(actual), "Expected a JSON Object value."); + + parcJSONValue_Release(&actual); + parcJSONParser_Release(&parser); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_ObjectParser_Bad_Pair) +{ + char *string = "{ \"name\" , \"name2\" : 2 }"; + PARCBuffer *buffer = parcBuffer_WrapCString(string); + + PARCJSONParser *parser = parcJSONParser_Create(buffer); + PARCJSONValue *actual = parcJSONValue_ObjectParser(parser); + + assertNull(actual, "Expected parcJSONValue_ObjectParser to return NULL indicating failure"); + + parcJSONParser_Release(&parser); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_ObjectParser_Bad_Pair2) +{ + char *string = "{ 2 }"; + PARCBuffer *buffer = parcBuffer_WrapCString(string); + + PARCJSONParser *parser = parcJSONParser_Create(buffer); + PARCJSONValue *actual = parcJSONValue_ObjectParser(parser); + + assertNull(actual, "Expected parcJSONValue_ObjectParser to return NULL indicating failure"); + + parcJSONParser_Release(&parser); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_ArrayParser) +{ + char *string = "[ \"name\", 1, true, false, null, [ ], { } ]"; + PARCBuffer *buffer = parcBuffer_WrapCString(string); + + PARCJSONParser *parser = parcJSONParser_Create(buffer); + PARCJSONValue *actual = _parcJSONValue_ArrayParser(parser); + + assertTrue(parcJSONValue_IsArray(actual), "Expected a JSON Array value."); + + parcJSONValue_Release(&actual); + parcJSONParser_Release(&parser); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_NumberParser_BatchedFloat) +{ + struct test_values { + char *string; + char *expectedString; + long double floatValue; + int64_t integerValue; + long double floatTolerance; + } successful[] = { + { "0", "0", 0.0, 0, 0 }, + { " 1", "1", 1.0, 1, 0 }, + { "-1", "-1", -1.0, -1, 0 }, + { "1e1", "1e1", 1.0e1, 10, 0 }, + { "-2e1", "-2e1", -2.0e1, -2e1, 0 }, + { "-2e+1", "-2e1", -2.0e+1, -2e+1, 0 }, + { " 1.0", "1", 1.0, 1, 0 }, + { "3e-1", "3e-1", 3e-1, 0, 0.01e-1 }, + { "100e-2", "100e-2", 100e-2, 100e-2, 0.0001 }, + { "123.456e11", "123.456e11", 123.456e11, 12345600000000, 0.0001e11 }, + { "-0.0415e-12", "-0.0415e-12", -0.0415e-12, 0, 0.00001e-12 }, + { "-0.0415e12", "-0.0415e12", -0.0415e12, -41500000000, 0.00001e12 }, + { "-0.0415", "-0.0415", -0.0415, 0, 0.00001 }, + { "-3.0415", "-3.0415", -3.0415, -3, 0.00001 }, + { "123.456", "123.456", 123.456, 123, 0.0001 }, + { "123.456e+11", "123.456e11", 123.456e+11, 12345600000000, 0.0001e+11 }, + { "123.456e-11", "123.456e-11", 123.456e-11, 0, 0.0001e-11 }, + { "1e-1", "1e-1", 1e-1, 0, 0.1e-1 }, + { NULL }, + }; + + for (int i = 0; successful[i].string != NULL; i++) { + PARCBuffer *buffer = parcBuffer_WrapCString(successful[i].string); + PARCJSONParser *parser = parcJSONParser_Create(buffer); + parcBuffer_Release(&buffer); + + PARCJSONValue *expected = _parcJSONValue_NumberParser(parser); + assertNotNull(expected, "_parcJSONValue_NumberParser returned NULL"); + + long double floatValue = parcJSONValue_GetFloat(expected); + + assertTrue(fabsl(floatValue - successful[i].floatValue) <= successful[i].floatTolerance, + "Expected %Lf actual %Lf", successful[i].floatValue, floatValue); + + char *string = parcJSONValue_ToString(expected); + assertTrue(strcmp(successful[i].expectedString, string) == 0, + "Expected %s actual %s", successful[i].expectedString, string); + parcMemory_Deallocate((void **) &string); + + int64_t integerValue = parcJSONValue_GetInteger(expected); + assertTrue(integerValue == (int64_t) successful[i].integerValue, + "Expected %" PRIi64 " actual %" PRIi64 "", (int64_t) successful[i].integerValue, integerValue); + + parcJSONValue_Release(&expected); + parcJSONParser_Release(&parser); + } +} + +LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_Comma) +{ + char *string = ", null"; + PARCBuffer *buffer = parcBuffer_WrapCString(string); + + PARCJSONParser *parser = parcJSONParser_Create(buffer); + PARCJSONValue *actual = parcJSONValue_Parser(parser); + + assertNull(actual, "Expected parcJSONValue_Parser to return NULL when encountering a comma"); + + parcJSONParser_Release(&parser); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_CloseBracket) +{ + char *string = "], null"; + PARCBuffer *buffer = parcBuffer_WrapCString(string); + + PARCJSONParser *parser = parcJSONParser_Create(buffer); + PARCJSONValue *actual = parcJSONValue_Parser(parser); + + assertNull(actual, "Expected parcJSONValue_Parser to return NULL when encountering a ]"); + + parcJSONParser_Release(&parser); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_Null) +{ + char *string = " null"; + PARCBuffer *buffer = parcBuffer_WrapCString(string); + + PARCJSONParser *parser = parcJSONParser_Create(buffer); + PARCJSONValue *actual = parcJSONValue_Parser(parser); + + assertTrue(parcJSONValue_IsNull(actual), + "Expected parcJSONValue_Parser to return a Null JSON value when encountering 'null'"); + + parcJSONValue_Release(&actual); + parcJSONParser_Release(&parser); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_True) +{ + char *string = " true"; + PARCBuffer *buffer = parcBuffer_WrapCString(string); + + PARCJSONParser *parser = parcJSONParser_Create(buffer); + PARCJSONValue *actual = parcJSONValue_Parser(parser); + + assertTrue(parcJSONValue_IsBoolean(actual), + "Expected parcJSONValue_Parser to return a boolean JSON value when encountering 'true'"); + assertTrue(parcJSONValue_GetBoolean(actual), + "Expected true"); + + parcJSONValue_Release(&actual); + parcJSONParser_Release(&parser); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_False) +{ + char *string = " false"; + PARCBuffer *buffer = parcBuffer_WrapCString(string); + + PARCJSONParser *parser = parcJSONParser_Create(buffer); + PARCJSONValue *actual = parcJSONValue_Parser(parser); + + assertTrue(parcJSONValue_IsBoolean(actual), + "Expected parcJSONValue_Parser to return a boolean JSON value when encountering 'false'"); + assertFalse(parcJSONValue_GetBoolean(actual), + "Expected true"); + + parcJSONValue_Release(&actual); + parcJSONParser_Release(&parser); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_String) +{ + char *string = " \"string\""; + PARCBuffer *buffer = parcBuffer_WrapCString(string); + + PARCJSONParser *parser = parcJSONParser_Create(buffer); + PARCJSONValue *actual = parcJSONValue_Parser(parser); + + assertTrue(parcJSONValue_IsString(actual), + "Expected parcJSONValue_Parser to return a string JSON value"); + + parcJSONValue_Release(&actual); + parcJSONParser_Release(&parser); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_Array) +{ + char *string = " [ ]"; + PARCBuffer *buffer = parcBuffer_WrapCString(string); + + PARCJSONParser *parser = parcJSONParser_Create(buffer); + PARCJSONValue *value = parcJSONValue_Parser(parser); + + assertTrue(parcJSONValue_IsArray(value), + "Expected parcJSONValue_Parser to return a array JSON value"); + + PARCJSONArray *array = parcJSONValue_GetArray(value); + assertNotNull(array, "Expected a non-null pointer to a PARCJSONArray"); + + parcJSONValue_Release(&value); + parcJSONParser_Release(&parser); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_Object) +{ + char *string = " { }"; + PARCBuffer *buffer = parcBuffer_WrapCString(string); + + PARCJSONParser *parser = parcJSONParser_Create(buffer); + PARCJSONValue *actual = parcJSONValue_Parser(parser); + + assertTrue(parcJSONValue_IsJSON(actual), + "Expected parcJSONValue_Parser to return a JSON object value"); + + parcJSONValue_Release(&actual); + parcJSONParser_Release(&parser); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_FIXTURE(Static) +{ + LONGBOW_RUN_TEST_CASE(Static, _parseSign_Negative); + LONGBOW_RUN_TEST_CASE(Static, _parseSign_NotASign); + LONGBOW_RUN_TEST_CASE(Static, _parseSign_Nil); + + LONGBOW_RUN_TEST_CASE(Static, _parseWholeNumber); + LONGBOW_RUN_TEST_CASE(Static, _parseOptionalFraction); + LONGBOW_RUN_TEST_CASE(Static, _parseOptionalExponent); +} + +LONGBOW_TEST_FIXTURE_SETUP(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Static, _parseSign_Negative) +{ + char *string = "-"; + + PARCBuffer *buffer = parcBuffer_WrapCString(string); + PARCJSONParser *parser = parcJSONParser_Create(buffer); + parcBuffer_Release(&buffer); + int sign; + bool result = _parseSign(parser, &sign); + + assertTrue(result, "Expected true from _parseSign()"); + + parcJSONParser_Release(&parser); +} + +LONGBOW_TEST_CASE(Static, _parseSign_NotASign) +{ + char *string = "asd"; + + PARCBuffer *buffer = parcBuffer_WrapCString(string); + PARCJSONParser *parser = parcJSONParser_Create(buffer); + parcBuffer_Release(&buffer); + int sign; + bool result = _parseSign(parser, &sign); + + assertFalse(result, "Expected true from _parseSign()"); + + parcJSONParser_Release(&parser); +} + +LONGBOW_TEST_CASE(Static, _parseSign_Nil) +{ + char *string = ""; + + PARCBuffer *buffer = parcBuffer_WrapCString(string); + PARCJSONParser *parser = parcJSONParser_Create(buffer); + parcBuffer_Release(&buffer); + int sign; + bool result = _parseSign(parser, &sign); + + assertTrue(result, "Expected true from _parseSign()"); + + parcJSONParser_Release(&parser); +} + +LONGBOW_TEST_CASE(Static, _parseWholeNumber) +{ + struct test_values { + char *string; + long double value; + } successful[] = { + { "0", 0 }, + { "1", 1 }, + { "123", 123 }, + { NULL }, + }; + + for (int i = 0; successful[i].string != NULL; i++) { + PARCBuffer *buffer = parcBuffer_WrapCString(successful[i].string); + PARCJSONParser *parser = parcJSONParser_Create(buffer); + parcBuffer_Release(&buffer); + + int64_t value = 0; + + bool actual = _parseWholeNumber(parser, &value); + + assertTrue(actual, "Expected true from _parseNumber()"); + assertTrue(value == successful[i].value, + "Expected %Lf actual %" PRIi64 "", successful[i].value, value); + parcJSONParser_Release(&parser); + } +} + +LONGBOW_TEST_CASE(Static, _parseOptionalFraction) +{ + struct test_values { + char *string; + long double value; + bool correct; + } successful[] = { + { ".0", 0, true }, + { ".", 0, false }, + { ".1", 1, true }, + { "crap", 0, false }, + { "}", 0, true }, + { NULL }, + }; + + for (int i = 0; successful[i].string != NULL; i++) { + PARCBuffer *buffer = parcBuffer_WrapCString(successful[i].string); + PARCJSONParser *parser = parcJSONParser_Create(buffer); + parcBuffer_Release(&buffer); + + int64_t value = 0; + int log10OfFraction; + + bool actual = _parseOptionalFraction(parser, &value, &log10OfFraction); + + assertTrue(actual == successful[i].correct, "Expected true from _parseNumber()"); + assertTrue(value == successful[i].value, + "Expected %Lf actual %" PRIi64 "", successful[i].value, value); + parcJSONParser_Release(&parser); + } +} + +LONGBOW_TEST_CASE(Static, _parseOptionalExponent) +{ + struct test_values { + char *string; + long double value; + bool correct; + } successful[] = { + { "e", 0, false }, + { "ex", 0, false }, + { "e-1", -1, true }, + { "e1", 1, true }, + { "e+1", 1, true }, + { "x", 0, false }, + { NULL }, + }; + + for (int i = 0; successful[i].string != NULL; i++) { + PARCBuffer *buffer = parcBuffer_WrapCString(successful[i].string); + PARCJSONParser *parser = parcJSONParser_Create(buffer); + parcBuffer_Release(&buffer); + + int64_t value = 0; + + bool actual = _parseOptionalExponent(parser, &value); + + assertTrue(actual == successful[i].correct, "Expected true from _parseNumber()"); + assertTrue(value == successful[i].value, + "Expected %Lf actual %" PRIi64 "", successful[i].value, value); + parcJSONParser_Release(&parser); + } +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_JSONValue); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_KeyValue.c b/libparc/parc/algol/test/test_parc_KeyValue.c new file mode 100755 index 00000000..f9440602 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_KeyValue.c @@ -0,0 +1,386 @@ +/* + * 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 <LongBow/unit-test.h> + +#include <stdio.h> + +#include <parc/algol/parc_SafeMemory.h> +#include <parc/testing/parc_ObjectTesting.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../parc_KeyValue.c" + + +LONGBOW_TEST_RUNNER(parc_KeyValue) +{ + // 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(PARCKeyValueAsPARCObject); + 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(parc_KeyValue) +{ + 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(parc_KeyValue) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(PARCKeyValueAsPARCObject) +{ + LONGBOW_RUN_TEST_CASE(PARCKeyValueAsPARCObject, parcObject_Conformance); +} + +LONGBOW_TEST_FIXTURE_SETUP(PARCKeyValueAsPARCObject) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(PARCKeyValueAsPARCObject) +{ + 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(PARCKeyValueAsPARCObject, parcObject_Conformance) +{ + PARCBuffer *key = parcBuffer_WrapCString("Key_1"); + PARCBuffer *value = parcBuffer_WrapCString("Value"); + PARCKeyValue *inst1 = parcKeyValue_Create(key, value); + PARCKeyValue *inst2 = parcKeyValue_Create(key, value); + PARCKeyValue *inst3 = parcKeyValue_Create(key, value); + parcBuffer_Release(&key); + parcBuffer_Release(&value); + + key = parcBuffer_WrapCString("Key_0"); + value = parcBuffer_WrapCString("Value"); + PARCKeyValue *lesser = parcKeyValue_Create(key, value); + parcBuffer_Release(&key); + parcBuffer_Release(&value); + + key = parcBuffer_WrapCString("Key_2"); + value = parcBuffer_WrapCString("Value"); + PARCKeyValue *greater = parcKeyValue_Create(key, value); + parcBuffer_Release(&key); + parcBuffer_Release(&value); + + parcObjectTesting_AssertObjectConformance(inst1, inst2, inst3, lesser, greater); + + parcKeyValue_Release(&inst1); + parcKeyValue_Release(&inst2); + parcKeyValue_Release(&inst3); + parcKeyValue_Release(&lesser); + parcKeyValue_Release(&greater); +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_Create); + LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_Acquire); + LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_Equals); + LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_Compare); + LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_HashCode); + LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_Copy); + LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_GetKey); + LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_GetValue); + LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_EqualKeys); + LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_SetKey); + LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_SetValue); +} + +typedef struct { + PARCKeyValue *testKV1; + PARCKeyValue *testKV2; + PARCKeyValue *nullValue; + PARCBuffer *key1; + PARCBuffer *value1; + PARCBuffer *key2; + PARCBuffer *value2; +} TestData; + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + + data->key1 = parcBuffer_WrapCString("This is key 1"); + data->value1 = parcBuffer_WrapCString("This is value 1"); + data->key2 = parcBuffer_WrapCString("This is key 2"); + data->value2 = parcBuffer_WrapCString("This is value 2"); + + data->testKV1 = parcKeyValue_Create(data->key1, data->value1); + data->testKV2 = parcKeyValue_Create(data->key2, data->value2); + + PARCBuffer *nullKey = parcBuffer_WrapCString("NULL KEY"); + data->nullValue = parcKeyValue_Create(nullKey, NULL); + parcBuffer_Release(&nullKey); + + longBowTestCase_SetClipBoardData(testCase, data); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + parcBuffer_Release(&data->key1); + parcBuffer_Release(&data->value1); + parcBuffer_Release(&data->key2); + parcBuffer_Release(&data->value2); + + parcKeyValue_Release(&data->testKV1); + parcKeyValue_Release(&data->testKV2); + parcKeyValue_Release(&data->nullValue); + + parcMemory_Deallocate((void **) &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, parcKeyValue_Create) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + assertNotNull(data->testKV1, "Expect a non-NULL key value"); +} + +LONGBOW_TEST_CASE(Global, parcKeyValue_Acquire) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + assertNotNull(data->testKV1, "Expect a non-NULL key value"); + + PARCKeyValue *kv = parcKeyValue_Acquire(data->testKV1); + parcKeyValue_Release(&kv); +} + +LONGBOW_TEST_CASE(Global, parcKeyValue_GetKey) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + assertTrue(parcBuffer_Equals(parcKeyValue_GetKey(data->testKV1), data->key1), + "The key returned is not the key provided"); + + assertNotNull(parcKeyValue_GetKey(data->nullValue), "Expect Non-NULL key from NULL value kv"); +} + +LONGBOW_TEST_CASE(Global, parcKeyValue_GetValue) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + assertTrue(parcBuffer_Equals(parcKeyValue_GetValue(data->testKV1), data->value1), + "The key returned is not the key provided"); + + assertNull(parcKeyValue_GetValue(data->nullValue), "Expect NULL from GetValue"); +} + +LONGBOW_TEST_CASE(Global, parcKeyValue_Equals) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + bool isEqual = parcKeyValue_Equals(data->testKV1, data->testKV2); + assertFalse(isEqual, "Expect test key-values to not be equal"); + + PARCKeyValue *kv = parcKeyValue_Create(data->key1, data->value2); + isEqual = parcKeyValue_Equals(kv, data->testKV1) || parcKeyValue_Equals(kv, data->testKV2); + parcKeyValue_Release(&kv); + assertFalse(isEqual, "Expect test key-values to not be equal"); + + kv = parcKeyValue_Create(data->key1, data->value1); + isEqual = parcKeyValue_Equals(kv, data->testKV1) && !parcKeyValue_Equals(kv, data->testKV2); + parcKeyValue_Release(&kv); + + assertTrue(isEqual, "Expect test key-values to be equal"); + + // NULL values + isEqual = parcKeyValue_Equals(data->testKV1, data->nullValue); + assertFalse(isEqual, "Expect NULL key-valuet to not be equal"); + + kv = parcKeyValue_Copy(data->nullValue); + isEqual = parcKeyValue_Equals(kv, data->nullValue); + assertTrue(isEqual, "Expect NULL key-valuet to not be equal"); + parcKeyValue_Release(&kv); +} + +LONGBOW_TEST_CASE(Global, parcKeyValue_Compare) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + assertTrue(parcKeyValue_Compare(NULL, NULL) == 0, "Expect 0 from comparing NULLs"); + assertTrue(parcKeyValue_Compare(data->testKV1, NULL) > 0, "Expect result > 0 from comparing non-NULL to NULL"); + assertTrue(parcKeyValue_Compare(NULL, data->testKV1) < 0, "Expect result < 0 from comparing NULL to non-NULL"); + + int result = parcKeyValue_Compare(data->testKV1, data->testKV2); + assertTrue(result < 0, "Expect compareison to be < 0"); + + result = parcKeyValue_Compare(data->testKV2, data->testKV1); + assertTrue(result > 0, "Expect compareison to be > 0"); + + // Mixed keys & values + PARCKeyValue *kv = parcKeyValue_Create(data->key1, data->value2); + result = parcKeyValue_Compare(kv, data->testKV1); + assertTrue(result == 0, "Expect comparison to be 0"); + + result = parcKeyValue_Compare(kv, data->testKV2); + assertTrue(result < 0, "Expect comparison to be < 0"); + + parcKeyValue_Release(&kv); + + // NULL value + result = parcKeyValue_Compare(data->testKV1, data->nullValue); + assertTrue(result > 0, "Expect NULL key-value be > 0"); +} + +LONGBOW_TEST_CASE(Global, parcKeyValue_HashCode) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCHashCode hash1 = parcKeyValue_HashCode(data->testKV1); + PARCHashCode hash2 = parcKeyValue_HashCode(data->testKV2); + assertFalse(hash1 == hash2, "Expect hash codes to be different"); + + PARCKeyValue *kv = parcKeyValue_Create(data->key1, data->value1); + hash2 = parcKeyValue_HashCode(kv); + assertTrue(hash1 == hash2, "Expect hash codes to be equal"); + parcKeyValue_Release(&kv); + + // Mixed keys & values + kv = parcKeyValue_Create(data->key1, data->value2); + hash2 = parcKeyValue_HashCode(kv); + assertTrue(hash1 == hash2, "Expect hash codes to be equal"); + parcKeyValue_Release(&kv); + + // NULL value + PARCHashCode hash = parcKeyValue_HashCode(data->nullValue); + assertTrue(hash != 0, "Expect NULL key-value hash to != 0"); +} + +LONGBOW_TEST_CASE(Global, parcKeyValue_EqualKeys) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + assertFalse(parcKeyValue_EqualKeys(data->testKV1, data->testKV2), "Expect keys to be different"); + + PARCKeyValue *kv = parcKeyValue_Create(data->key1, data->value2); + + assertTrue(parcKeyValue_EqualKeys(data->testKV1, kv), "Expect keys to be equal"); + + parcKeyValue_Release(&kv); + + // NULL value + assertFalse(parcKeyValue_EqualKeys(data->nullValue, data->testKV1), "Expect NULL key-value hash to != 0"); +} + +LONGBOW_TEST_CASE(Global, parcKeyValue_SetKey) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + parcKeyValue_SetKey(data->testKV2, data->key1); + + assertTrue(parcKeyValue_EqualKeys(data->testKV1, data->testKV2), + "Expect kv keys to be equal after SetKey"); + + // NULL value + parcKeyValue_SetKey(data->nullValue, data->key1); + assertTrue(parcKeyValue_EqualKeys(data->testKV1, data->nullValue), + "Expect kv keys to be equal after SetKey"); +} + +LONGBOW_TEST_CASE(Global, parcKeyValue_SetValue) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + parcKeyValue_SetValue(data->testKV2, data->value1); + + assertTrue(parcBuffer_Equals(parcKeyValue_GetValue(data->testKV1), + parcKeyValue_GetValue(data->testKV2)), + "Expect kv values to be equal after SetValue"); + + // NULL value + parcKeyValue_SetValue(data->testKV2, NULL); + assertNull(parcKeyValue_GetValue(data->testKV2), + "Expect NULL for testKV2 after SetValue"); + + parcKeyValue_SetValue(data->nullValue, data->value1); + assertTrue(parcBuffer_Equals(parcKeyValue_GetValue(data->testKV1), + parcKeyValue_GetValue(data->nullValue)), + "Expect kv values to be equal after SetValue"); +} + +LONGBOW_TEST_CASE(Global, parcKeyValue_Copy) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCKeyValue *kv = parcKeyValue_Copy(data->testKV1); + assertTrue(parcKeyValue_Equals(kv, data->testKV1), + "Expect key-value copy to be equal to original key-value"); + + parcKeyValue_Release(&kv); + + // NULL value + kv = parcKeyValue_Copy(data->nullValue); + assertTrue(parcKeyValue_Equals(kv, data->nullValue), + "Expect key-value copy to be equal to original key-value"); + + parcKeyValue_Release(&kv); +} + +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[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_KeyValue); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_KeyedElement.c b/libparc/parc/algol/test/test_parc_KeyedElement.c new file mode 100755 index 00000000..a6866437 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_KeyedElement.c @@ -0,0 +1,134 @@ +/* + * 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 "../parc_KeyedElement.c" + +#include <LongBow/unit-test.h> +#include <stdio.h> + +#include <parc/algol/parc_SafeMemory.h> + +LONGBOW_TEST_RUNNER(parc_KeyedElement) +{ + // 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(parc_KeyedElement) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_KeyedElement) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcKeyedElement_CreateDestroy); + LONGBOW_RUN_TEST_CASE(Global, parcKeyedElement_GetData); + LONGBOW_RUN_TEST_CASE(Global, parcKeyedElement_GetKey); + LONGBOW_RUN_TEST_CASE(Global, parcKeyedElement_SetData); +} + +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, parcKeyedElement_CreateDestroy) +{ + char *key1 = "key001"; + size_t keylen1 = 7; + PARCKeyedElement *keyedElement = parcKeyedElement_Create("Some data", key1, keylen1); + parcKeyedElement_Destroy(&keyedElement); +} + +LONGBOW_TEST_CASE(Global, parcKeyedElement_GetData) +{ + char *initial_data = "some data here"; + char *key1 = "key001"; + size_t keylen1 = 7; + PARCKeyedElement *keyedElement = parcKeyedElement_Create(initial_data, key1, keylen1); + char *data = parcKeyedElement_GetData(keyedElement); + assertTrue(initial_data == data, "We got different data from element"); + parcKeyedElement_Destroy(&keyedElement); +} + +LONGBOW_TEST_CASE(Global, parcKeyedElement_GetKey) +{ + char *initial_data = "some data here"; + char *key1 = "key001"; + size_t keylen1 = 7; + PARCKeyedElement *keyedElement = parcKeyedElement_Create(initial_data, key1, keylen1); + char *thekey = parcKeyedElement_GetKey(keyedElement); + size_t thekeylen = parcKeyedElement_GetKeyLen(keyedElement); + assertTrue(keylen1 == thekeylen, "We got different key size?"); + assertTrue(memcmp(key1, thekey, keylen1) == 0, "We got different keys?"); + parcKeyedElement_Destroy(&keyedElement); +} + +LONGBOW_TEST_CASE(Global, parcKeyedElement_SetData) +{ + char *key1 = "key001"; + size_t keylen1 = 7; + char *initial_data = "some data here"; + + PARCKeyedElement *keyedElement = parcKeyedElement_Create("Hello World", key1, keylen1); + + parcKeyedElement_SetData(keyedElement, initial_data); + char *data = parcKeyedElement_GetData(keyedElement); + assertTrue(initial_data == data, "We got different data from element"); + parcKeyedElement_Destroy(&keyedElement); +} + +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[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_KeyedElement); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_LinkedList.c b/libparc/parc/algol/test/test_parc_LinkedList.c new file mode 100644 index 00000000..294f2ea2 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_LinkedList.c @@ -0,0 +1,1192 @@ +/* + * 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 "../parc_LinkedList.c" + +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> +#include <parc/algol/parc_StdlibMemory.h> + +#include <parc/testing/parc_ObjectTesting.h> +#include <parc/testing/parc_MemoryTesting.h> + +LONGBOW_TEST_RUNNER(PARCLinkedList) +{ + // 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(Local); + LONGBOW_RUN_TEST_FIXTURE(AcquireRelease); + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Performance); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(PARCLinkedList) +{ + 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(PARCLinkedList) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(AcquireRelease) +{ + LONGBOW_RUN_TEST_CASE(AcquireRelease, parcLinkedList_CreateRelease); + LONGBOW_RUN_TEST_CASE(AcquireRelease, parcLinkedList_AcquireRelease); +} + +LONGBOW_TEST_FIXTURE_SETUP(AcquireRelease) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(AcquireRelease) +{ + bool leaked = parcMemoryTesting_ExpectedOutstanding(0, "%s leaks memory \n", longBowTestCase_GetName(testCase)) != true; + if (leaked) { + parcSafeMemory_ReportAllocation(STDOUT_FILENO); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(AcquireRelease, parcLinkedList_CreateRelease) +{ + PARCLinkedList *deque = parcLinkedList_Create(); + assertNotNull(deque, "Expected non-null result from parcLinkedList_Create()"); + + assertTrue(parcLinkedList_IsValid(deque), "Expected created PARCLinkedList to be valid."); + + parcLinkedList_Release(&deque); + assertNull(deque, "Expected parcLinkedList_Release to null the pointer"); +} + +LONGBOW_TEST_CASE(AcquireRelease, parcLinkedList_AcquireRelease) +{ + PARCLinkedList *original = parcLinkedList_Create(); + assertNotNull(original, "Expected non-null result from parcLinkedList_Create()"); + + parcObjectTesting_AssertAcquireReleaseContract(parcLinkedList_Acquire, original); + + PARCLinkedList *reference = parcLinkedList_Acquire(original); + assertTrue(original == reference, "Expected the reference to be equal to the original."); + + parcLinkedList_Release(&original); + assertNull(original, "Expected parcLinkedList_Release to null the pointer"); + + PARCBuffer *object = parcBuffer_Allocate(11); + parcLinkedList_Append(reference, object); + parcBuffer_Release(&object); + + size_t expected = 1; + size_t actual = parcLinkedList_Size(reference); + assertTrue(expected == actual, + "Expected size %zd, actual %zd", expected, actual); + parcLinkedList_Release(&reference); +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_AssertValid); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_HashCode); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Append_One); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Append_Two); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_AppendAll); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_AppendAll_None); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_CreateDestroy); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_GetFirst); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_GetLast); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_SetAtIndex); + + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Prepend_One); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Prepend_Two); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Prepend_Three); + + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_IsEmpty); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_GetAtIndex); + + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Contains_True); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Contains_False); + + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_RemoveFirst); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_RemoveFirst_SingleElement); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_RemoveLast); + + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Remove); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_RemoveNotFound); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_RemoveAtIndex); + + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Size); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Equals); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Copy); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_InsertAtIndex_Head); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_InsertAtIndex_HeadEmptyList); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_InsertAtIndex_Tail); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_InsertAtIndex_Middle); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Display); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Display_NULL); + + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_CreateIterator); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_CreateIterator_Remove); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_CreateIterator_RemoveHead); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_CreateIterator_RemoveMiddle); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_CreateIterator_RemoveTail); + + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_SetEquals_True); + LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_SetEquals_False); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + bool leaked = parcMemoryTesting_ExpectedOutstanding(0, "%s leaks memory \n", longBowTestCase_GetName(testCase)) != true; + if (leaked) { + parcSafeMemory_ReportAllocation(STDOUT_FILENO); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_AssertValid) +{ + PARCLinkedList *list = parcLinkedList_Create(); + + parcLinkedList_AssertValid(list); + parcLinkedList_Release(&list); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_Append_One) +{ + PARCLinkedList *list = parcLinkedList_Create(); + + PARCBuffer *object = parcBuffer_Allocate(11); + PARCLinkedList *actual = parcLinkedList_Append(list, object); + parcBuffer_Release(&object); + + assertTrue(parcLinkedList_IsValid(list), "PARCLinkedList is invalid."); + + assertTrue(list == actual, "Expected parcLinkedList_Append to return its argument."); + assertTrue(parcLinkedList_Size(list) == 1, "Expected size of 1, actual %zd", parcLinkedList_Size(list)); + + parcLinkedList_Release(&list); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_Append_Two) +{ + PARCLinkedList *deque = parcLinkedList_Create(); + + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCBuffer *object2 = parcBuffer_WrapCString("2"); + + parcLinkedList_Append(deque, object1); + PARCLinkedList *actual = parcLinkedList_Append(deque, object2); + parcBuffer_Release(&object1); + parcBuffer_Release(&object2); + + assertTrue(deque == actual, "Expected parcLinkedList_Append to return its argument."); + assertTrue(parcLinkedList_Size(deque) == 2, "Expected size of 2, actual %zd", parcLinkedList_Size(deque)); + + parcLinkedList_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_AppendAll) +{ + PARCLinkedList *other = parcLinkedList_Create(); + + for (int i = 0; i < 1000; i++) { + PARCBuffer *buffer = parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), i); + parcLinkedList_Append(other, buffer); + parcBuffer_Release(&buffer); + } + + PARCLinkedList *list = parcLinkedList_Create(); + + parcLinkedList_AppendAll(list, other); + + assertTrue(parcLinkedList_Equals(list, other), "Expected equal lists."); + + parcLinkedList_Release(&list); + parcLinkedList_Release(&other); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_AppendAll_None) +{ + PARCLinkedList *other = parcLinkedList_Create(); + + PARCLinkedList *list = parcLinkedList_Create(); + + parcLinkedList_AppendAll(list, other); + + assertTrue(parcLinkedList_Equals(list, other), "Expected equal lists."); + + parcLinkedList_Release(&list); + parcLinkedList_Release(&other); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_CreateDestroy) +{ + PARCLinkedList *deque = parcLinkedList_Create(); + assertNotNull(deque, "Expected non-null result from parcLinkedList_Create()"); + + parcLinkedList_Release(&deque); + assertNull(deque, "Expected parcLinkedList_Destroy to null the pointer"); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_HashCode) +{ + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCBuffer *object2 = parcBuffer_WrapCString("2"); + PARCBuffer *object3 = parcBuffer_WrapCString("3"); + + PARCLinkedList *deque = parcLinkedList_Create(); + parcLinkedList_Append(deque, object1); + parcLinkedList_Append(deque, object2); + parcLinkedList_Append(deque, object3); + + parcLinkedList_HashCode(deque); + + parcBuffer_Release(&object1); + parcBuffer_Release(&object2); + parcBuffer_Release(&object3); + parcLinkedList_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_GetFirst) +{ + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCBuffer *object2 = parcBuffer_WrapCString("2"); + PARCBuffer *object3 = parcBuffer_WrapCString("3"); + + PARCLinkedList *deque = parcLinkedList_Create(); + parcLinkedList_Append(deque, object1); + parcLinkedList_Append(deque, object2); + parcLinkedList_Append(deque, object3); + + PARCBuffer *actual = parcLinkedList_GetFirst(deque); + assertTrue(parcBuffer_Equals(object1, actual), "Order of objects in the list is wrong."); + + parcBuffer_Release(&object1); + parcBuffer_Release(&object2); + parcBuffer_Release(&object3); + parcLinkedList_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_GetLast) +{ + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCBuffer *object2 = parcBuffer_WrapCString("2"); + PARCBuffer *object3 = parcBuffer_WrapCString("3"); + + PARCLinkedList *deque = parcLinkedList_Create(); + parcLinkedList_Append(deque, object1); + parcLinkedList_Append(deque, object2); + parcLinkedList_Append(deque, object3); + + PARCBuffer *actual = parcLinkedList_GetLast(deque); + assertTrue(parcBuffer_Equals(object3, actual), "Order of objects in the list is wrong."); + + parcBuffer_Release(&object1); + parcBuffer_Release(&object2); + parcBuffer_Release(&object3); + parcLinkedList_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_Prepend_One) +{ + PARCLinkedList *deque = parcLinkedList_Create(); + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCLinkedList *actual = parcLinkedList_Prepend(deque, object1); + parcBuffer_Release(&object1); + + assertTrue(deque == actual, "Expected parcLinkedList_Append to return its argument."); + assertTrue(parcLinkedList_Size(deque) == 1, "Expected size of 1, actual %zd", parcLinkedList_Size(deque)); + assertTrue(deque->head != NULL, "Expected head to be not null."); + assertTrue(deque->head == deque->tail, "Expected head to be equal to the tail."); + + parcLinkedList_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_Prepend_Two) +{ + PARCLinkedList *deque = parcLinkedList_Create(); + + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCLinkedList *actual = parcLinkedList_Prepend(deque, object1); + parcLinkedList_Prepend(deque, object1); + parcBuffer_Release(&object1); + + assertTrue(deque == actual, "Expected parcLinkedList_Prepend to return its argument."); + assertTrue(parcLinkedList_Size(deque) == 2, "Expected size of 2, actual %zd", parcLinkedList_Size(deque)); + + parcLinkedList_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_Prepend_Three) +{ + PARCLinkedList *deque = parcLinkedList_Create(); + + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCBuffer *object2 = parcBuffer_WrapCString("2"); + PARCBuffer *object3 = parcBuffer_WrapCString("3"); + parcLinkedList_Prepend(deque, object1); + parcLinkedList_Prepend(deque, object2); + PARCLinkedList *actual = parcLinkedList_Prepend(deque, object3); + + assertTrue(deque == actual, "Expected parcLinkedList_Prepend to return its argument."); + assertTrue(parcLinkedList_Size(deque) == 3, "Expected size of 3, actual %zd", parcLinkedList_Size(deque)); + + PARCBuffer *peek = parcLinkedList_GetFirst(deque); + assertTrue(parcBuffer_Equals(object3, peek), "Order of objects failed"); + + peek = parcLinkedList_GetLast(deque); + assertTrue(parcBuffer_Equals(object1, peek), "Order of objects failed"); + + parcBuffer_Release(&object1); + parcBuffer_Release(&object2); + parcBuffer_Release(&object3); + + parcLinkedList_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_RemoveFirst) +{ + PARCLinkedList *list = parcLinkedList_Create(); + + for (int i = 0; i < 1000; i++) { + PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), i)); + parcLinkedList_Append(list, buffer); + parcBuffer_Release(&buffer); + } + + PARCBuffer *peek = parcLinkedList_RemoveFirst(list); + assertTrue(parcObject_GetReferenceCount(peek) == 1, "Expected reference count to be 1."); + assertTrue(parcBuffer_GetUint32(peek) == 0, "Objects out of order."); + + parcBuffer_Release(&peek); + parcLinkedList_Release(&list); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_RemoveFirst_SingleElement) +{ + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCLinkedList *deque = parcLinkedList_Create(); + parcLinkedList_Prepend(deque, object1); + + PARCBuffer *peek = parcLinkedList_RemoveFirst(deque); + assertTrue(parcBuffer_Equals(object1, peek), + "Objects out of order."); + + parcBuffer_Release(&peek); + parcBuffer_Release(&object1); + parcLinkedList_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_RemoveLast) +{ + PARCLinkedList *list = parcLinkedList_Create(); + + for (int i = 0; i < 1000; i++) { + PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), i)); + parcLinkedList_Append(list, buffer); + parcBuffer_Release(&buffer); + } + + PARCBuffer *peek = parcLinkedList_RemoveLast(list); + assertTrue(parcObject_GetReferenceCount(peek) == 1, "Expected reference count to be 1."); + assertTrue(parcBuffer_GetUint32(peek) == 999, "Objects out of order."); + + parcBuffer_Release(&peek); + parcLinkedList_Release(&list); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_RemoveLast_SingleElement) +{ + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + + PARCLinkedList *deque = parcLinkedList_Create(); + parcLinkedList_Prepend(deque, object1); + + PARCBuffer *peek = parcLinkedList_RemoveLast(deque); + assertTrue(parcBuffer_Equals(object1, peek), + "Objects out of order."); + + parcBuffer_Release(&object1); + parcLinkedList_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_Remove) +{ + PARCLinkedList *deque = parcLinkedList_Create(); + + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCBuffer *object2 = parcBuffer_WrapCString("2"); + PARCBuffer *object3 = parcBuffer_WrapCString("3"); + + parcLinkedList_Prepend(deque, object3); + parcLinkedList_Prepend(deque, object2); + parcLinkedList_Prepend(deque, object1); + + bool found = parcLinkedList_Remove(deque, object2); + assertTrue(found, "Expected item to be found"); + assertTrue(parcLinkedList_Size(deque) == 2, "Expected size of 2, actual %zd", parcLinkedList_Size(deque)); + + PARCBuffer *peek; + peek = parcLinkedList_RemoveFirst(deque); + assertTrue(parcBuffer_Equals(object1, peek), "Object1 was not first in list"); + parcBuffer_Release(&peek); + + peek = parcLinkedList_RemoveFirst(deque); + assertTrue(parcBuffer_Equals(object3, peek), "Object3 was not second in list"); + parcBuffer_Release(&peek); + + parcBuffer_Release(&object1); + parcBuffer_Release(&object2); + parcBuffer_Release(&object3); + parcLinkedList_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_RemoveAtIndex) +{ + PARCLinkedList *list = parcLinkedList_Create(); + + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCBuffer *object2 = parcBuffer_WrapCString("2"); + PARCBuffer *object3 = parcBuffer_WrapCString("3"); + + parcLinkedList_Prepend(list, object3); + parcLinkedList_Prepend(list, object2); + parcLinkedList_Prepend(list, object1); + + PARCBuffer *actual = parcLinkedList_RemoveAtIndex(list, 1); + + assertTrue(parcBuffer_Equals(object2, actual), "Wrong object returned from parcLinkedList_RemoveAtIndex"); + + parcBuffer_Release(&object1); + parcBuffer_Release(&object2); + parcBuffer_Release(&object3); + parcBuffer_Release(&actual); + parcLinkedList_Release(&list); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_RemoveNotFound) +{ + PARCLinkedList *deque = parcLinkedList_Create(); + + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCBuffer *object2 = parcBuffer_WrapCString("2"); + PARCBuffer *object3 = parcBuffer_WrapCString("3"); + PARCBuffer *object4 = parcBuffer_WrapCString("4"); + + parcLinkedList_Prepend(deque, object3); + parcLinkedList_Prepend(deque, object2); + parcLinkedList_Prepend(deque, object1); + + bool found = parcLinkedList_Remove(deque, object4); + assertFalse(found, "Expected item to be not found"); + assertTrue(parcLinkedList_Size(deque) == 3, "Expected size of 3, actual %zd", parcLinkedList_Size(deque)); + + parcBuffer_Release(&object1); + parcBuffer_Release(&object2); + parcBuffer_Release(&object3); + parcBuffer_Release(&object4); + parcLinkedList_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_Size) +{ + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCBuffer *object2 = parcBuffer_WrapCString("2"); + PARCBuffer *object3 = parcBuffer_WrapCString("3"); + + PARCLinkedList *deque = parcLinkedList_Create(); + parcLinkedList_Prepend(deque, object1); + parcLinkedList_Prepend(deque, object2); + parcLinkedList_Prepend(deque, object3); + + assertTrue(parcLinkedList_Size(deque) == 3, + "Expected 3, actual %zd", parcLinkedList_Size(deque)); + + parcBuffer_Release(&object1); + parcBuffer_Release(&object2); + parcBuffer_Release(&object3); + + parcLinkedList_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_IsEmpty) +{ + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + + PARCLinkedList *deque = parcLinkedList_Create(); + + assertTrue(parcLinkedList_IsEmpty(deque), "Expected true."); + parcLinkedList_Prepend(deque, object1); + assertFalse(parcLinkedList_IsEmpty(deque), "Expected false."); + + parcBuffer_Release(&object1); + parcLinkedList_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_GetAtIndex) +{ + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCBuffer *object2 = parcBuffer_WrapCString("2"); + PARCBuffer *object3 = parcBuffer_WrapCString("3"); + + PARCLinkedList *deque = parcLinkedList_Create(); + parcLinkedList_Append(deque, object1); + parcLinkedList_Append(deque, object2); + parcLinkedList_Append(deque, object3); + + PARCBuffer *actual; + actual = parcLinkedList_GetAtIndex(deque, 0); + assertTrue(parcBuffer_Equals(actual, object1), "parcLinkedList_GetAtIndex failed"); + actual = parcLinkedList_GetAtIndex(deque, 1); + assertTrue(parcBuffer_Equals(actual, object2), "parcLinkedList_GetAtIndex failed"); + actual = parcLinkedList_GetAtIndex(deque, 2); + assertTrue(parcBuffer_Equals(actual, object3), "parcLinkedList_GetAtIndex failed"); + + parcBuffer_Release(&object1); + parcBuffer_Release(&object2); + parcBuffer_Release(&object3); + parcLinkedList_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_SetAtIndex) +{ + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCBuffer *object2 = parcBuffer_WrapCString("2"); + PARCBuffer *object3 = parcBuffer_WrapCString("3"); + + PARCLinkedList *deque = parcLinkedList_Create(); + parcLinkedList_Append(deque, object1); + parcLinkedList_Append(deque, object2); + parcLinkedList_Append(deque, object3); + + PARCBuffer *newObject = parcBuffer_WrapCString("Hello"); + + PARCBuffer *actual = parcLinkedList_SetAtIndex(deque, 0, newObject); + assertTrue(parcBuffer_Equals(actual, object1), "parcLinkedList_SetAtIndex failed to return the old value."); + parcBuffer_Release(&actual); + + actual = parcLinkedList_GetAtIndex(deque, 0); + assertTrue(parcBuffer_Equals(actual, newObject), "parcLinkedList_SetAtIndex failed to set the new value."); + + parcBuffer_Release(&newObject); + parcBuffer_Release(&object1); + parcBuffer_Release(&object2); + parcBuffer_Release(&object3); + parcLinkedList_Release(&deque); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_Contains_True) +{ + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCBuffer *object2 = parcBuffer_WrapCString("2"); + PARCBuffer *object3 = parcBuffer_WrapCString("3"); + + PARCLinkedList *list = parcLinkedList_Create(); + parcLinkedList_Append(list, object1); + parcLinkedList_Append(list, object2); + parcLinkedList_Append(list, object3); + + bool actual = parcLinkedList_Contains(list, object2); + assertTrue(actual, "Expected parcLinkedList_Contains to return true for object in the list"); + + parcBuffer_Release(&object1); + parcBuffer_Release(&object2); + parcBuffer_Release(&object3); + parcLinkedList_Release(&list); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_Contains_False) +{ + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCBuffer *object2 = parcBuffer_WrapCString("2"); + PARCBuffer *object3 = parcBuffer_WrapCString("3"); + + PARCLinkedList *list = parcLinkedList_Create(); + parcLinkedList_Append(list, object1); + parcLinkedList_Append(list, object3); + + bool actual = parcLinkedList_Contains(list, object2); + assertFalse(actual, "Expected parcLinkedList_Contains to return false for object not in the list"); + + parcBuffer_Release(&object1); + parcBuffer_Release(&object2); + parcBuffer_Release(&object3); + parcLinkedList_Release(&list); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_Equals) +{ + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCBuffer *object2 = parcBuffer_WrapCString("2"); + PARCBuffer *object3 = parcBuffer_WrapCString("3"); + + PARCLinkedList *x = parcLinkedList_Create(); + parcLinkedList_Append(x, object1); + parcLinkedList_Append(x, object2); + PARCLinkedList *y = parcLinkedList_Create(); + parcLinkedList_Append(y, object1); + parcLinkedList_Append(y, object2); + PARCLinkedList *z = parcLinkedList_Create(); + parcLinkedList_Append(z, object1); + parcLinkedList_Append(z, object2); + PARCLinkedList *u1 = parcLinkedList_Create(); + parcLinkedList_Append(u1, object2); + PARCLinkedList *u2 = parcLinkedList_Create(); + parcLinkedList_Append(u2, object2); + parcLinkedList_Append(u2, object3); + + parcObjectTesting_AssertEqualsFunction(parcLinkedList_Equals, x, y, z, u1, u2, NULL); + + parcLinkedList_Release(&x); + parcLinkedList_Release(&y); + parcLinkedList_Release(&z); + parcLinkedList_Release(&u1); + parcLinkedList_Release(&u2); + + parcBuffer_Release(&object1); + parcBuffer_Release(&object2); + parcBuffer_Release(&object3); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_Copy) +{ + PARCLinkedList *x = parcLinkedList_Create(); + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCBuffer *object2 = parcBuffer_WrapCString("2"); + PARCBuffer *object3 = parcBuffer_WrapCString("3"); + parcLinkedList_Append(x, object1); + parcLinkedList_Append(x, object2); + parcLinkedList_Append(x, object3); + + PARCLinkedList *y = parcLinkedList_Copy(x); + + assertTrue(parcLinkedList_Equals(x, y), "Expected the copy to be equal to the original."); + + assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid."); + + parcBuffer_Release(&object1); + parcBuffer_Release(&object2); + parcBuffer_Release(&object3); + + parcLinkedList_Release(&y); + parcLinkedList_Release(&x); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_InsertAtIndex_Head) +{ + PARCLinkedList *x = parcLinkedList_Create(); + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCBuffer *object2 = parcBuffer_WrapCString("2"); + PARCBuffer *object3 = parcBuffer_WrapCString("3"); + PARCBuffer *object4 = parcBuffer_WrapCString("4"); + parcLinkedList_Append(x, object1); + parcLinkedList_Append(x, object2); + parcLinkedList_Append(x, object3); + + parcLinkedList_InsertAtIndex(x, 0, object4); + + PARCBuffer *actual = parcLinkedList_GetAtIndex(x, 0); + + assertTrue(actual == object4, "Unexpected object at index 0"); + + assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid."); + + parcBuffer_Release(&object1); + parcBuffer_Release(&object2); + parcBuffer_Release(&object3); + parcBuffer_Release(&object4); + + parcLinkedList_Release(&x); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_InsertAtIndex_HeadEmptyList) +{ + PARCLinkedList *x = parcLinkedList_Create(); + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCBuffer *object2 = parcBuffer_WrapCString("2"); + PARCBuffer *object3 = parcBuffer_WrapCString("3"); + PARCBuffer *object4 = parcBuffer_WrapCString("4"); + + parcLinkedList_InsertAtIndex(x, 0, object4); + assertTrue(x->head->object == object4, "Malformed linked list node does not contain the proper object reference"); + assertTrue(x->head == x->tail, "Expected the list head and tail to be the same for a single element list."); + assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid."); + + PARCBuffer *actual = parcLinkedList_GetAtIndex(x, 0); + + assertTrue(actual == object4, "Unexpected object at index 0"); + + parcBuffer_Release(&object1); + parcBuffer_Release(&object2); + parcBuffer_Release(&object3); + parcBuffer_Release(&object4); + + parcLinkedList_Release(&x); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_InsertAtIndex_Tail) +{ + PARCLinkedList *x = parcLinkedList_Create(); + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCBuffer *object2 = parcBuffer_WrapCString("2"); + PARCBuffer *object3 = parcBuffer_WrapCString("3"); + PARCBuffer *object4 = parcBuffer_WrapCString("4"); + parcLinkedList_Append(x, object1); + parcLinkedList_Append(x, object2); + parcLinkedList_Append(x, object3); + + parcLinkedList_InsertAtIndex(x, 3, object4); + assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid."); + + PARCBuffer *actual = parcLinkedList_GetAtIndex(x, 3); + + assertTrue(actual == object4, "Unexpected object at index 3"); + + parcBuffer_Release(&object1); + parcBuffer_Release(&object2); + parcBuffer_Release(&object3); + parcBuffer_Release(&object4); + + parcLinkedList_Release(&x); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_InsertAtIndex_Middle) +{ + PARCLinkedList *x = parcLinkedList_Create(); + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCBuffer *object2 = parcBuffer_WrapCString("2"); + PARCBuffer *object3 = parcBuffer_WrapCString("3"); + PARCBuffer *object4 = parcBuffer_WrapCString("4"); + parcLinkedList_Append(x, object1); + parcLinkedList_Append(x, object2); + parcLinkedList_Append(x, object3); + + parcLinkedList_InsertAtIndex(x, 1, object4); + assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid."); + + assertTrue(parcLinkedList_GetAtIndex(x, 0) == object1, "Unexpected object at index 1"); + assertTrue(parcLinkedList_GetAtIndex(x, 1) == object4, "Unexpected object at index 1"); + assertTrue(parcLinkedList_GetAtIndex(x, 2) == object2, "Unexpected object at index 1"); + assertTrue(parcLinkedList_GetAtIndex(x, 3) == object3, "Unexpected object at index 1"); + + parcBuffer_Release(&object1); + parcBuffer_Release(&object2); + parcBuffer_Release(&object3); + parcBuffer_Release(&object4); + + parcLinkedList_Release(&x); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_Display) +{ + PARCLinkedList *x = parcLinkedList_Create(); + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCBuffer *object2 = parcBuffer_WrapCString("2"); + PARCBuffer *object3 = parcBuffer_WrapCString("3"); + parcLinkedList_Append(x, object1); + parcLinkedList_Append(x, object2); + parcLinkedList_Append(x, object3); + + parcLinkedList_Display(x, 0); + + parcBuffer_Release(&object1); + parcBuffer_Release(&object2); + parcBuffer_Release(&object3); + parcLinkedList_Release(&x); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_Display_NULL) +{ + parcLinkedList_Display(NULL, 0); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_CreateIterator) +{ + PARCLinkedList *x = parcLinkedList_Create(); + + uint32_t expectedCount = 10; + for (uint32_t i = 0; i < expectedCount; i++) { + PARCBuffer *object = parcBuffer_Allocate(sizeof(int)); + parcBuffer_PutUint32(object, i); + parcBuffer_Flip(object); + parcLinkedList_Append(x, object); + parcBuffer_Release(&object); + } + + PARCIterator *iterator = parcLinkedList_CreateIterator(x); + uint32_t expected = 0; + while (parcIterator_HasNext(iterator)) { + PARCBuffer *buffer = (PARCBuffer *) parcIterator_Next(iterator); + uint32_t actual = parcBuffer_GetUint32(buffer); + assertTrue(expected == actual, "Expected %d, actual %d", expected, actual); + expected++; + } + parcIterator_Release(&iterator); + + parcLinkedList_Release(&x); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_CreateIterator_Remove) +{ + PARCLinkedList *x = parcLinkedList_Create(); + for (size_t i = 0; i < 5; i++) { + PARCBuffer *buffer = parcBuffer_Allocate(10); + parcBuffer_PutUint64(buffer, i); + parcBuffer_Flip(buffer); + parcLinkedList_Append(x, buffer); + parcBuffer_Release(&buffer); + } + + assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid."); + + PARCIterator *iterator = parcLinkedList_CreateIterator(x); + size_t expected = 0; + while (parcIterator_HasNext(iterator)) { + size_t actual = parcBuffer_GetUint64(parcIterator_Next(iterator)); + assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual); + parcIterator_Remove(iterator); + expected++; + } + parcIterator_Release(&iterator); + + iterator = parcLinkedList_CreateIterator(x); + assertFalse(parcIterator_HasNext(iterator), "Expected an interator on an empty list to not HaveNext"); + parcIterator_Release(&iterator); + + assertTrue(parcLinkedList_Size(x) == 0, "List is not empty."); + + assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid."); + parcLinkedList_Release(&x); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_CreateIterator_RemoveHead) +{ + size_t listSize = 5; + + PARCLinkedList *x = parcLinkedList_Create(); + for (size_t i = 0; i < listSize; i++) { + PARCBuffer *buffer = parcBuffer_Allocate(10); + parcBuffer_PutUint64(buffer, i); + parcBuffer_Flip(buffer); + parcLinkedList_Append(x, buffer); + parcBuffer_Release(&buffer); + } + + assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid."); + parcLinkedList_Display(x, 0); + + PARCIterator *iterator = parcLinkedList_CreateIterator(x); + if (parcIterator_HasNext(iterator)) { + PARCBuffer *buffer = (PARCBuffer *) parcIterator_Next(iterator); + size_t actual = parcBuffer_GetUint64(buffer); + assertTrue(actual == 0, "Expected %d, actual %zd", 0, actual); + parcIterator_Remove(iterator); + } + parcIterator_Release(&iterator); + + iterator = parcLinkedList_CreateIterator(x); + assertTrue(parcIterator_HasNext(iterator), "Expected an interator on a non-empty list to HaveNext"); + parcIterator_Release(&iterator); + + assertTrue(parcLinkedList_Size(x) == listSize - 1, "Expected the list to be %zd, actual %zd", listSize - 1, parcLinkedList_Size(x)); + + assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid."); + parcLinkedList_Release(&x); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_CreateIterator_RemoveMiddle) +{ + size_t listSize = 5; + + PARCLinkedList *x = parcLinkedList_Create(); + for (size_t i = 0; i < listSize; i++) { + PARCBuffer *buffer = parcBuffer_Allocate(10); + parcBuffer_PutUint64(buffer, i); + parcBuffer_Flip(buffer); + parcLinkedList_Append(x, buffer); + parcBuffer_Release(&buffer); + } + + assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid."); + assertTrue(parcLinkedList_Size(x) == listSize, "Expected the list to be %zd, actual %zd", listSize, parcLinkedList_Size(x)); + + + PARCIterator *iterator = parcLinkedList_CreateIterator(x); + for (size_t i = 0; i <= listSize / 2; i++) { + if (parcIterator_HasNext(iterator)) { + parcIterator_Next(iterator); + } + } + parcIterator_Remove(iterator); + + parcIterator_Release(&iterator); + + + iterator = parcLinkedList_CreateIterator(x); + size_t expected = 0; + while (parcIterator_HasNext(iterator)) { + if (expected != (listSize / 2)) { + size_t actual = parcBuffer_GetUint64(parcIterator_Next(iterator)); + assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual); + } + expected++; + } + parcIterator_Release(&iterator); + + assertTrue(parcLinkedList_Size(x) == listSize - 1, "Expected the list to be %zd, actual %zd", listSize - 1, parcLinkedList_Size(x)); + + assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid."); + parcLinkedList_Release(&x); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_CreateIterator_RemoveTail) +{ + size_t listSize = 5; + + PARCLinkedList *x = parcLinkedList_Create(); + for (size_t i = 0; i < listSize; i++) { + PARCBuffer *buffer = parcBuffer_Allocate(10); + parcBuffer_PutUint64(buffer, i); + parcBuffer_Flip(buffer); + parcLinkedList_Append(x, buffer); + parcBuffer_Release(&buffer); + } + + assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid."); + assertTrue(parcLinkedList_Size(x) == listSize, "Expected the list to be %zd, actual %zd", listSize, parcLinkedList_Size(x)); + + PARCIterator *iterator = parcLinkedList_CreateIterator(x); + for (size_t i = 0; i < listSize; i++) { + if (parcIterator_HasNext(iterator)) { + parcIterator_Next(iterator); + } + } + parcIterator_Remove(iterator); + + parcIterator_Release(&iterator); + + assertTrue(parcLinkedList_Size(x) == listSize - 1, "Expected the list to be %zd, actual %zd", listSize - 1, parcLinkedList_Size(x)); + + + iterator = parcLinkedList_CreateIterator(x); + size_t expected = 0; + while (parcIterator_HasNext(iterator)) { + size_t actual = parcBuffer_GetUint64(parcIterator_Next(iterator)); + assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual); + expected++; + } + parcIterator_Release(&iterator); + + assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid."); + parcLinkedList_Release(&x); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_SetEquals_True) +{ + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCBuffer *object2 = parcBuffer_WrapCString("2"); + PARCBuffer *object3 = parcBuffer_WrapCString("3"); + + PARCLinkedList *x = parcLinkedList_Create(); + parcLinkedList_Append(x, object1); + parcLinkedList_Append(x, object2); + PARCLinkedList *y = parcLinkedList_Create(); + parcLinkedList_Append(y, object2); + parcLinkedList_Append(y, object1); + + PARCLinkedList *u1 = parcLinkedList_Create(); + parcLinkedList_Append(u1, object2); + + PARCLinkedList *u2 = parcLinkedList_Create(); + parcLinkedList_Append(u2, object2); + parcLinkedList_Append(u2, object3); + + assertTrue(parcLinkedList_SetEquals(x, y), "Expected to lists with the same elements to be equal regarless of order."); + + parcLinkedList_Release(&x); + parcLinkedList_Release(&y); + parcLinkedList_Release(&u1); + parcLinkedList_Release(&u2); + + parcBuffer_Release(&object1); + parcBuffer_Release(&object2); + parcBuffer_Release(&object3); +} + +LONGBOW_TEST_CASE(Global, parcLinkedList_SetEquals_False) +{ + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCBuffer *object2 = parcBuffer_WrapCString("2"); + PARCBuffer *object3 = parcBuffer_WrapCString("3"); + + PARCLinkedList *x = parcLinkedList_Create(); + parcLinkedList_Append(x, object1); + parcLinkedList_Append(x, object2); + + PARCLinkedList *u1 = parcLinkedList_Create(); + parcLinkedList_Append(u1, object2); + + PARCLinkedList *u2 = parcLinkedList_Create(); + parcLinkedList_Append(u2, object2); + parcLinkedList_Append(u2, object3); + + assertFalse(parcLinkedList_SetEquals(x, u1), "Expected to lists without the same elements to be equal regarless of order."); + + parcLinkedList_Release(&x); + parcLinkedList_Release(&u1); + parcLinkedList_Release(&u2); + + parcBuffer_Release(&object1); + parcBuffer_Release(&object2); + parcBuffer_Release(&object3); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, _parcLinkedListNode_Create); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + bool leaked = parcMemoryTesting_ExpectedOutstanding(0, "%s leaks memory \n", longBowTestCase_GetName(testCase)) != true; + if (leaked) { + parcSafeMemory_ReportAllocation(STDOUT_FILENO); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, _parcLinkedListNode_Create) +{ + PARCBuffer *object = parcBuffer_Allocate(10); + struct parc_linkedlist_node *previous = NULL; + struct parc_linkedlist_node *next = NULL; + + struct parc_linkedlist_node *actual = _parcLinkedListNode_Create(object, previous, next); + parcBuffer_Release(&object); + _parcLinkedListNode_Destroy(NULL, &actual); +} + +LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false) +{ + LONGBOW_RUN_TEST_CASE(Performance, parcLinkedList_Append); + LONGBOW_RUN_TEST_CASE(Performance, parcLinkedList_N2); + LONGBOW_RUN_TEST_CASE(Performance, parcLinkedList_CreateIterator); +} + +LONGBOW_TEST_FIXTURE_SETUP(Performance) +{ + parcMemory_SetInterface(&PARCStdlibMemoryAsPARCMemory); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Performance) +{ + 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(Performance, parcLinkedList_Append) +{ + PARCLinkedList *x = parcLinkedList_Create(); + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + + for (size_t i = 0; i < 100000; i++) { + parcLinkedList_Append(x, object1); + } + + parcBuffer_Release(&object1); + parcLinkedList_Release(&x); +} + +LONGBOW_TEST_CASE(Performance, parcLinkedList_N2) +{ + PARCLinkedList *x = parcLinkedList_Create(); + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + + for (size_t i = 0; i < 100000; i++) { + parcLinkedList_Append(x, object1); + } + + for (size_t expected = 0; expected < parcLinkedList_Size(x); expected++) { + PARCBuffer *actual = (PARCBuffer *) parcLinkedList_GetAtIndex(x, expected); + assertTrue(parcBuffer_Equals(object1, actual), "Mismatched value in the list."); + } + + parcBuffer_Release(&object1); + + parcLinkedList_Release(&x); +} + +LONGBOW_TEST_CASE(Performance, parcLinkedList_CreateIterator) +{ + PARCLinkedList *x = parcLinkedList_Create(); + + uint32_t expectedCount = 100000; + for (uint32_t i = 0; i < expectedCount; i++) { + PARCBuffer *object = parcBuffer_Allocate(sizeof(int)); + parcBuffer_PutUint32(object, i); + parcBuffer_Flip(object); + parcLinkedList_Append(x, object); + parcBuffer_Release(&object); + } + + PARCIterator *iterator = parcLinkedList_CreateIterator(x); + uint32_t expected = 0; + while (parcIterator_HasNext(iterator)) { + PARCBuffer *buffer = (PARCBuffer *) parcIterator_Next(iterator); + uint32_t actual = parcBuffer_GetUint32(buffer); + assertTrue(expected == actual, "Expected %d, actual %d", expected, actual); + expected++; + } + parcIterator_Release(&iterator); + + parcLinkedList_Release(&x); +} + + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(PARCLinkedList); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_List.c b/libparc/parc/algol/test/test_parc_List.c new file mode 100644 index 00000000..59a7d136 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_List.c @@ -0,0 +1,872 @@ +/* + * 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 "../parc_List.c" +#include <LongBow/unit-test.h> + +#include <stdio.h> +#include <string.h> + +#include <parc/testing/parc_MemoryTesting.h> +#include <parc/algol/parc_SafeMemory.h> + +#include <parc/algol/parc_ArrayList.h> +#include <parc/algol/parc_LinkedList.h> +#include <parc/testing/parc_ObjectTesting.h> + +LONGBOW_TEST_RUNNER(PARCList) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(PARCList); + LONGBOW_RUN_TEST_FIXTURE(Local); +// LONGBOW_RUN_TEST_FIXTURE(Errors); +} + +LONGBOW_TEST_RUNNER_SETUP(PARCList) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(PARCList) +{ + 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; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, PARCList_Add); + LONGBOW_RUN_TEST_CASE(Global, PARCList_AddAll); + LONGBOW_RUN_TEST_CASE(Global, PARCList_Copy); + LONGBOW_RUN_TEST_CASE(Global, parcList_Release); + + LONGBOW_RUN_TEST_CASE(Global, PARCList_Equals_Contract); + LONGBOW_RUN_TEST_CASE(Global, PARCList_Equals_Contract_Deep); + + LONGBOW_RUN_TEST_CASE(Global, PARCList_FromInitialCapacity); + LONGBOW_RUN_TEST_CASE(Global, PARCList_Get); + LONGBOW_RUN_TEST_CASE(Global, PARCList_New); + LONGBOW_RUN_TEST_CASE(Global, PARCList_Length); + LONGBOW_RUN_TEST_CASE(Global, PARCList_Remove_AtIndex_First); + LONGBOW_RUN_TEST_CASE(Global, PARCList_Remove_AtIndex); + LONGBOW_RUN_TEST_CASE(Global, PARCList_Remove_AtIndex_Last); + LONGBOW_RUN_TEST_CASE(Global, PARCList_RemoveAndDestroy_AtIndex_First); + LONGBOW_RUN_TEST_CASE(Global, PARCList_RemoveAndDestroy_AtIndex); + LONGBOW_RUN_TEST_CASE(Global, PARCList_RemoveAndDestroy_AtIndex_Last); + LONGBOW_RUN_TEST_CASE(Global, PARCList_InsertAtIndex); + LONGBOW_RUN_TEST_CASE(Global, PARCList_InsertAtIndex_Empty); + LONGBOW_RUN_TEST_CASE(Global, PARCList_InsertAtIndex_First); + LONGBOW_RUN_TEST_CASE(Global, PARCList_InsertAtIndex_Last); + LONGBOW_RUN_TEST_CASE(Global, PARCList_IsEmpty); +} + +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, PARCList_Add) +{ + PARCList *list = parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction), PARCArrayListAsPARCList); + + parcList_Add(list, 0); + size_t actual = parcList_Size(list); + assertTrue(1 == actual, "Expected=%d, actual=%zu", 1, actual); + + parcList_Release(&list); +} + +LONGBOW_TEST_CASE(Global, PARCList_AddAll) +{ + PARCList *list = parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction), PARCArrayListAsPARCList); + + void *elements[] = { + strdup("a"), + strdup("b"), + strdup("c"), + }; + + parcList_AddAll(list, 3, elements); + size_t actual = parcList_Size(list); + + assertTrue(3 == actual, "Expected=%d, actual=%zu", 3, actual); + + parcList_Release(&list); +} + +LONGBOW_TEST_CASE(Global, PARCList_Copy) +{ + char *a = strdup("apple"); + char *b = strdup("bananna"); + char *c = strdup("cherry"); + + PARCList *list = parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction), PARCArrayListAsPARCList); + + parcList_Add(list, a); + parcList_Add(list, b); + parcList_Add(list, c); + + parcList_Release(&list); +} + +LONGBOW_TEST_CASE(Global, parcList_Release) +{ + PARCList *list = parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction), PARCArrayListAsPARCList); + + parcList_Release(&list); + assertNull(list, "Expected null."); +} + +LONGBOW_TEST_CASE(Global, PARCList_Equals_Empty) +{ + PARCArrayList *a = parcArrayList_Create(parcArrayList_StdlibFreeFunction); + PARCArrayList *b = parcArrayList_Create(parcArrayList_StdlibFreeFunction); + assertTrue(parcArrayList_Equals(a, b), "Equal values were expected to be equal"); + + parcArrayList_Destroy(&a); + parcArrayList_Destroy(&b); +} + +LONGBOW_TEST_CASE(Global, PARCList_Equals_Same) +{ + PARCArrayList *a = parcArrayList_Create(parcArrayList_StdlibFreeFunction); + assertTrue(parcArrayList_Equals(a, a), "Expected the same array list to be equal to itself."); + + parcArrayList_Destroy(&a); +} + +LONGBOW_TEST_CASE(Global, PARCList_Equals_Contract) +{ + char a[] = "apple"; + char b[] = "bananna"; + char c[] = "cherry"; + char d[] = "potato"; + + PARCArrayList *x = parcArrayList_Create(NULL); + parcArrayList_Add(x, a); + parcArrayList_Add(x, b); + parcArrayList_Add(x, c); + + PARCArrayList *y = parcArrayList_Create(NULL); + parcArrayList_Add(y, a); + parcArrayList_Add(y, b); + parcArrayList_Add(y, c); + + PARCArrayList *z = parcArrayList_Create(NULL); + parcArrayList_Add(z, a); + parcArrayList_Add(z, b); + parcArrayList_Add(z, c); + + PARCArrayList *u1 = parcArrayList_Create(NULL); + parcArrayList_Add(u1, a); + parcArrayList_Add(u1, b); + + PARCArrayList *u2 = parcArrayList_Create(NULL); + parcArrayList_Add(u1, a); + parcArrayList_Add(u2, b); + parcArrayList_Add(u2, c); + parcArrayList_Add(u2, c); + + PARCArrayList *u3 = parcArrayList_Create(NULL); + parcArrayList_Add(u3, a); + parcArrayList_Add(u3, b); + parcArrayList_Add(u3, d); + + parcObjectTesting_AssertEqualsFunction(parcArrayList_Equals, x, y, z, u1, u2, u3); + + parcArrayList_Destroy(&x); + parcArrayList_Destroy(&y); + parcArrayList_Destroy(&z); + parcArrayList_Destroy(&u1); + parcArrayList_Destroy(&u2); + parcArrayList_Destroy(&u3); +} + +static bool +stringEquals(void *x, void *y) +{ + return strcmp((char *) x, (char *) y) == 0; +} + +LONGBOW_TEST_CASE(Global, PARCList_Equals_Contract_Deep) +{ + char a[] = "apple"; + char b[] = "bananna"; + char c[] = "cherry"; + char d[] = "potato"; + + PARCArrayList *x = parcArrayList_Create_Capacity(stringEquals, NULL, 0); + parcArrayList_Add(x, a); + parcArrayList_Add(x, b); + parcArrayList_Add(x, c); + + PARCArrayList *y = parcArrayList_Create_Capacity(stringEquals, NULL, 0); + parcArrayList_Add(y, a); + parcArrayList_Add(y, b); + parcArrayList_Add(y, c); + + PARCArrayList *z = parcArrayList_Create_Capacity(stringEquals, NULL, 0); + parcArrayList_Add(z, a); + parcArrayList_Add(z, b); + parcArrayList_Add(z, c); + + PARCArrayList *u1 = parcArrayList_Create_Capacity(stringEquals, NULL, 0); + parcArrayList_Add(u1, a); + parcArrayList_Add(u1, b); + + PARCArrayList *u2 = parcArrayList_Create_Capacity(stringEquals, NULL, 0); + parcArrayList_Add(u2, a); + parcArrayList_Add(u2, b); + parcArrayList_Add(u2, c); + parcArrayList_Add(u2, c); + + PARCArrayList *u3 = parcArrayList_Create_Capacity(stringEquals, NULL, 0); + parcArrayList_Add(u3, a); + parcArrayList_Add(u3, b); + parcArrayList_Add(u3, d); + + parcObjectTesting_AssertEqualsFunction(parcArrayList_Equals, x, y, z, u1, u2, u3); + + parcArrayList_Destroy(&x); + parcArrayList_Destroy(&y); + parcArrayList_Destroy(&z); + parcArrayList_Destroy(&u1); + parcArrayList_Destroy(&u2); + parcArrayList_Destroy(&u3); +} + +LONGBOW_TEST_CASE(Global, PARCList_FromInitialCapacity) +{ + PARCArrayList *array = parcArrayList_Create_Capacity(NULL, parcArrayList_StdlibFreeFunction, 10); + size_t actual = parcArrayList_Size(array); + + assertTrue(0 == actual, "Expected=%d, actual=%zu", 0, actual); + + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARCList_Get) +{ + PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction); + + char *expected = strdup("Hello World"); + parcArrayList_Add(array, expected); + + char *actual = parcArrayList_Get(array, 0); + + assertTrue(expected == actual, "Expected=%p, actual=%p", (void *) expected, (void *) actual); + + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARCList_New) +{ + PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction); + size_t size = parcArrayList_Size(array); + assertTrue(0 == size, "Expected %d actual=%zd", 0, size); + + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARCList_Length) +{ + PARCArrayList *array = parcArrayList_Create(NULL); + parcArrayList_Add(array, 0); + + size_t size = parcArrayList_Size(array); + assertTrue(1 == size, "Expected %d actual=%zd", 1, size); + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARCList_IsEmpty) +{ + PARCArrayList *array = parcArrayList_Create(NULL); + assertTrue(parcArrayList_IsEmpty(array), "Expected a new array to be empty."); + + parcArrayList_Add(array, 0); + assertFalse(parcArrayList_IsEmpty(array), "Expected an array with more than zero elements to be empty."); + + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARCList_InsertAtIndex) +{ + PARCArrayList *array = parcArrayList_Create(NULL); + + parcArrayList_Add(array, (void *) 1); + parcArrayList_Add(array, (void *) 2); + size_t actual = parcArrayList_Size(array); + + assertTrue(2 == actual, "Expected=%d, actual=%zu", 2, actual); + + parcArrayList_InsertAtIndex(array, 1, (void *) 3); + + actual = parcArrayList_Size(array); + assertTrue(3 == actual, "Expected=%d, actual=%zu", 3, actual); + + void *element0 = parcArrayList_Get(array, 0); + assertTrue(element0 == (void *) 1, "Element 1 moved?"); + + void *element1 = parcArrayList_Get(array, 1); + assertTrue(element1 == (void *) 3, "Element 1 moved?"); + + void *element2 = parcArrayList_Get(array, 2); + assertTrue(element2 == (void *) 2, "Element 1 moved?"); + + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARCList_InsertAtIndex_Empty) +{ + PARCArrayList *array = parcArrayList_Create(NULL); + + parcArrayList_InsertAtIndex(array, 0, (void *) 3); + + size_t actual = parcArrayList_Size(array); + + assertTrue(1 == actual, "Expected=%d, actual=%zu", 1, actual); + + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARCList_InsertAtIndex_First) +{ + PARCArrayList *array = parcArrayList_Create(NULL); + + parcArrayList_Add(array, (void *) 1); + parcArrayList_InsertAtIndex(array, 0, (void *) 2); + size_t actual = parcArrayList_Size(array); + + assertTrue(2 == actual, "Expected=%d, actual=%zu", 2, actual); + + void *element0 = parcArrayList_Get(array, 0); + assertTrue(element0 == (void *) 2, "Element 1 moved?"); + + void *element1 = parcArrayList_Get(array, 1); + assertTrue(element1 == (void *) 1, "Element 1 moved?"); + + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARCList_InsertAtIndex_Last) +{ + PARCArrayList *array = parcArrayList_Create(NULL); + + parcArrayList_Add(array, (void *) 1); + parcArrayList_Add(array, (void *) 2); + size_t actual = parcArrayList_Size(array); + + assertTrue(2 == actual, "Expected=%d, actual=%zu", 2, actual); + + parcArrayList_InsertAtIndex(array, 2, (void *) 3); + + actual = parcArrayList_Size(array); + assertTrue(3 == actual, "Expected=%d, actual=%zu", 3, actual); + + void *element0 = parcArrayList_Get(array, 0); + assertTrue(element0 == (void *) 1, "Element 1 moved?"); + + void *element1 = parcArrayList_Get(array, 1); + assertTrue(element1 == (void *) 2, "Element 1 moved?"); + + void *element2 = parcArrayList_Get(array, 2); + assertTrue(element2 == (void *) 3, "Element 1 moved?"); + + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARCList_Remove_AtIndex_First) +{ + char a[] = "apple"; + char b[] = "bananna"; + char c[] = "cherry"; + + PARCArrayList *array = parcArrayList_Create(NULL); + parcArrayList_Add(array, a); + parcArrayList_Add(array, b); + parcArrayList_Add(array, c); + + PARCArrayList *expected = parcArrayList_Create(NULL); + parcArrayList_Add(expected, b); + parcArrayList_Add(expected, c); + + void *removedElement = parcArrayList_RemoveAtIndex(array, 0); + + assertTrue(removedElement == a, "Expected "); + assertTrue(parcArrayList_Equals(expected, array), "Expected "); + + parcArrayList_Destroy(&expected); + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARCList_Remove_AtIndex) +{ + char a[] = "apple"; + char b[] = "bananna"; + char c[] = "cherry"; + + PARCArrayList *array = parcArrayList_Create(NULL); + parcArrayList_Add(array, a); + parcArrayList_Add(array, b); + parcArrayList_Add(array, c); + + PARCArrayList *expected = parcArrayList_Create(NULL); + parcArrayList_Add(expected, a); + parcArrayList_Add(expected, c); + + void *removedElement = parcArrayList_RemoveAtIndex(array, 1); + + assertTrue(removedElement == b, "Expected "); + assertTrue(parcArrayList_Equals(expected, array), "Expected "); + + parcArrayList_Destroy(&expected); + parcArrayList_Destroy(&array); +} + + +LONGBOW_TEST_CASE(Global, PARCList_Remove_AtIndex_Last) +{ + char a[] = "apple"; + char b[] = "bananna"; + char c[] = "cherry"; + + PARCArrayList *array = parcArrayList_Create(NULL); + parcArrayList_Add(array, a); + parcArrayList_Add(array, b); + parcArrayList_Add(array, c); + + PARCArrayList *expected = parcArrayList_Create(NULL); + parcArrayList_Add(expected, a); + parcArrayList_Add(expected, b); + + void *removedElement = parcArrayList_RemoveAtIndex(array, 2); + + assertTrue(removedElement == c, "Expected "); + assertTrue(parcArrayList_Equals(expected, array), "Expected "); + + parcArrayList_Destroy(&expected); + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARCList_RemoveAndDestroy_AtIndex_First) +{ + char a[] = "apple"; + char b[] = "bananna"; + char c[] = "cherry"; + + PARCArrayList *array = parcArrayList_Create(NULL); + parcArrayList_Add(array, a); + parcArrayList_Add(array, b); + parcArrayList_Add(array, c); + + PARCArrayList *expected = parcArrayList_Create(NULL); + parcArrayList_Add(expected, b); + parcArrayList_Add(expected, c); + + parcArrayList_RemoveAndDestroyAtIndex(array, 0); + + assertTrue(parcArrayList_Equals(expected, array), "Expected "); + + parcArrayList_Destroy(&expected); + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARCList_RemoveAndDestroy_AtIndex) +{ + char a[] = "apple"; + char b[] = "bananna"; + char c[] = "cherry"; + + PARCArrayList *array = parcArrayList_Create(NULL); + parcArrayList_Add(array, a); + parcArrayList_Add(array, b); + parcArrayList_Add(array, c); + + PARCArrayList *expected = parcArrayList_Create(NULL); + parcArrayList_Add(expected, a); + parcArrayList_Add(expected, c); + + parcArrayList_RemoveAndDestroyAtIndex(array, 1); + + assertTrue(parcArrayList_Equals(expected, array), "Expected "); + + parcArrayList_Destroy(&expected); + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(Global, PARCList_RemoveAndDestroy_AtIndex_Last) +{ + char a[] = "apple"; + char b[] = "bananna"; + char c[] = "cherry"; + + PARCArrayList *array = parcArrayList_Create(NULL); + parcArrayList_Add(array, a); + parcArrayList_Add(array, b); + parcArrayList_Add(array, c); + + PARCArrayList *expected = parcArrayList_Create(NULL); + parcArrayList_Add(expected, a); + parcArrayList_Add(expected, b); + + parcArrayList_RemoveAndDestroyAtIndex(array, 2); + + assertTrue(parcArrayList_Equals(expected, array), "Expected "); + + parcArrayList_Destroy(&expected); + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Errors) +{ + LONGBOW_RUN_TEST_CASE(Errors, PARCList_InsertAtIndex_OutOfCapacity); +} + +LONGBOW_TEST_FIXTURE_SETUP(Errors) +{ + PARCArrayList *array = parcArrayList_Create(NULL); + + longBowTestCase_SetClipBoardData(testCase, array); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Errors) +{ + PARCArrayList *array = longBowTestCase_GetClipBoardData(testCase); + parcArrayList_Destroy(&array); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + if (outstandingAllocations != 0) { + printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE_EXPECTS(Errors, PARCList_InsertAtIndex_OutOfCapacity, .event = &LongBowAssertEvent) +{ + PARCArrayList *array = longBowTestCase_GetClipBoardData(testCase); + + parcArrayList_Add(array, (void *) 1); + parcArrayList_Add(array, (void *) 2); + + parcArrayList_InsertAtIndex(array, 200, (void *) 3); +} + + +LONGBOW_TEST_FIXTURE(PARCList) +{ + LONGBOW_RUN_TEST_CASE(PARCList, parcList_Add); + LONGBOW_RUN_TEST_CASE(PARCList, parcList_AddCollection); + LONGBOW_RUN_TEST_CASE(PARCList, parcList_AddCollectionAtIndex); + LONGBOW_RUN_TEST_CASE(PARCList, parcList_Contains); + LONGBOW_RUN_TEST_CASE(PARCList, parcList_ContainsCollection); + LONGBOW_RUN_TEST_CASE(PARCList, parcList_Equals); + LONGBOW_RUN_TEST_CASE(PARCList, parcList_IsEmpty); + LONGBOW_RUN_TEST_CASE(PARCList, parcList_GetAtIndex); + LONGBOW_RUN_TEST_CASE(PARCList, parcList_Remove); + LONGBOW_RUN_TEST_CASE(PARCList, parcList_RemoveCollection); + LONGBOW_RUN_TEST_CASE(PARCList, parcList_RetainCollection); + LONGBOW_RUN_TEST_CASE(PARCList, parcList_HashCode); + LONGBOW_RUN_TEST_CASE(PARCList, parcList_IndexOf); + LONGBOW_RUN_TEST_CASE(PARCList, parcList_LastIndexOf); + LONGBOW_RUN_TEST_CASE(PARCList, parcList_Copy); + LONGBOW_RUN_TEST_CASE(PARCList, parcList_Clear); + LONGBOW_RUN_TEST_CASE(PARCList, parcList_Destroy); + LONGBOW_RUN_TEST_CASE(PARCList, parcList_RemoveAtIndex); + LONGBOW_RUN_TEST_CASE(PARCList, parcList_SetAtIndex); + LONGBOW_RUN_TEST_CASE(PARCList, parcList_Size); + LONGBOW_RUN_TEST_CASE(PARCList, parcList_SubList); + LONGBOW_RUN_TEST_CASE(PARCList, parcList_ToArray); +} + +LONGBOW_TEST_FIXTURE_SETUP(PARCList) +{ + longBowTestCase_SetInt(testCase, "initialAllocations", parcMemory_Outstanding()); + longBowTestCase_Set(testCase, "linkedList", parcLinkedList_Create()); + longBowTestCase_Set(testCase, "list", parcLinkedList_AsPARCList(longBowTestCase_Get(testCase, "linkedList"))); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(PARCList) +{ + PARCLinkedList *linkedList = longBowTestCase_Get(testCase, "linkedList"); + parcLinkedList_Release(&linkedList); + PARCList *list = longBowTestCase_Get(testCase, "list"); + parcList_Release(&list); + + int initialAllocations = longBowTestCase_GetInt(testCase, "initalAllocations"); + if (!parcMemoryTesting_ExpectedOutstanding(initialAllocations, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) { + parcSafeMemory_ReportAllocation(STDOUT_FILENO); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +//#include "test_parc_List_modular.c" + +LONGBOW_TEST_CASE(PARCList, parcList_Add) +{ + PARCList *list = longBowTestCase_Get(testCase, "list"); + + PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), 1)); + parcList_Add(list, buffer); + parcBuffer_Release(&buffer); + + size_t actual = parcList_Size(list); + assertTrue(1 == actual, "Expected=%d, actual=%zu", 1, actual); +} + +LONGBOW_TEST_CASE(PARCList, parcList_AddCollection) +{ +} + +LONGBOW_TEST_CASE(PARCList, parcList_AddCollectionAtIndex) +{ +} + +LONGBOW_TEST_CASE(PARCList, parcList_Contains) +{ +} + +LONGBOW_TEST_CASE(PARCList, parcList_ContainsCollection) +{ +} + +LONGBOW_TEST_CASE(PARCList, parcList_Equals) +{ + PARCList *list = longBowTestCase_Get(testCase, "list"); + PARCList *copy = parcList_Copy(list); + + assertTrue(parcList_Equals(list, copy), "Expected copy to be equal to the original."); + + parcList_Release(©); +} + +LONGBOW_TEST_CASE(PARCList, parcList_IsEmpty) +{ + PARCList *list = longBowTestCase_Get(testCase, "list"); + assertTrue(parcList_IsEmpty(list), "Expected list to be empty."); +} + +LONGBOW_TEST_CASE(PARCList, parcList_GetAtIndex) +{ + PARCList *list = longBowTestCase_Get(testCase, "list"); + + for (int i = 0; i < 1000; i++) { + PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), i)); + parcList_Add(list, buffer); + parcBuffer_Release(&buffer); + } + + uint32_t actual = parcBuffer_GetUint32(parcList_GetAtIndex(list, 0)); + + assertTrue(actual == 0, "Expected %u, actual %u\n", 0, actual); +} + +LONGBOW_TEST_CASE(PARCList, parcList_Remove) +{ + PARCList *list = longBowTestCase_Get(testCase, "list"); + + PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), 1)); + parcList_Add(list, buffer); + parcBuffer_Release(&buffer); + + buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), 1)); + + bool actual = parcList_Remove(list, buffer); + assertTrue(actual, "Expected element to have been found and removed."); + + parcBuffer_Release(&buffer); + + buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), 3)); + + actual = parcList_Remove(list, buffer); + assertFalse(actual, "Expected element to have not been found and removed."); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(PARCList, parcList_RemoveCollection) +{ +} + +LONGBOW_TEST_CASE(PARCList, parcList_RetainCollection) +{ +} + +LONGBOW_TEST_CASE(PARCList, parcList_HashCode) +{ + PARCList *list = longBowTestCase_Get(testCase, "list"); + parcList_HashCode(list); +} + +LONGBOW_TEST_CASE(PARCList, parcList_IndexOf) +{ + PARCList *list = longBowTestCase_Get(testCase, "list"); + + for (int i = 0; i < 1000; i++) { + PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), i)); + parcList_Add(list, buffer); + parcBuffer_Release(&buffer); + } + + uint32_t expected = 10; + PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), 10)); + size_t actual = parcList_IndexOf(list, buffer); + + parcBuffer_Release(&buffer); + + assertTrue(expected == actual, "Expected %u, actual %zu", expected, actual); +} + +LONGBOW_TEST_CASE(PARCList, parcList_LastIndexOf) +{ + PARCList *list = longBowTestCase_Get(testCase, "list"); + + for (int i = 0; i < 1000; i++) { + PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), 1)); + parcList_Add(list, buffer); + parcBuffer_Release(&buffer); + } + + uint32_t expected = 999; + PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), 1)); + size_t actual = parcList_LastIndexOf(list, buffer); + + parcBuffer_Release(&buffer); + + assertTrue(expected == actual, "Expected %u, actual %zu", expected, actual); +} + +LONGBOW_TEST_CASE(PARCList, parcList_Copy) +{ + PARCList *list = longBowTestCase_Get(testCase, "list"); + PARCList *copy = parcList_Copy(list); + + assertTrue(parcList_Equals(list, copy), "Expected copy to be equal to the original."); + + parcList_Release(©); +} + +LONGBOW_TEST_CASE(PARCList, parcList_Clear) +{ + PARCList *list = longBowTestCase_Get(testCase, "list"); + parcList_Clear(list); + + assertTrue(parcList_IsEmpty(list), "Expected list to be empty."); +} + +LONGBOW_TEST_CASE(PARCList, parcList_Destroy) +{ + PARCList *list = longBowTestCase_Get(testCase, "list"); + PARCList *copy = parcList_Copy(list); + + parcList_Release(©); +} + +LONGBOW_TEST_CASE(PARCList, parcList_RemoveAtIndex) +{ + PARCList *list = longBowTestCase_Get(testCase, "list"); + + for (int i = 0; i < 1000; i++) { + PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), i)); + parcList_Add(list, buffer); + parcBuffer_Release(&buffer); + } + + PARCBuffer *buffer = parcList_RemoveAtIndex(list, 0); + uint32_t actual = parcBuffer_GetUint32(buffer); + assertTrue(actual == 0, "Expected buffer 0."); + + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(PARCList, parcList_SetAtIndex) +{ + PARCList *list = longBowTestCase_Get(testCase, "list"); + + for (int i = 0; i < 1000; i++) { + PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), i)); + parcList_Add(list, buffer); + parcBuffer_Release(&buffer); + } + + PARCBuffer *buffer = parcBuffer_WrapCString("1"); + + PARCBuffer *oldValue = parcList_SetAtIndex(list, 50, buffer); + + PARCBuffer *actual = parcList_GetAtIndex(list, 50); + assertTrue(parcBuffer_Equals(buffer, actual), "parcList_SetAtIndex set the wrong location."); + parcBuffer_Release(&buffer); + parcBuffer_Release(&oldValue); +} + +LONGBOW_TEST_CASE(PARCList, parcList_Size) +{ + PARCArrayList *array = parcArrayList_Create(NULL); + parcArrayList_Add(array, 0); + + size_t size = parcArrayList_Size(array); + assertTrue(1 == size, "Expected %d actual=%zd", 1, size); + parcArrayList_Destroy(&array); +} + +LONGBOW_TEST_CASE(PARCList, parcList_SubList) +{ +} + +LONGBOW_TEST_CASE(PARCList, parcList_ToArray) +{ +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(PARCList); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_Memory.c b/libparc/parc/algol/test/test_parc_Memory.c new file mode 100755 index 00000000..5fb18ce3 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_Memory.c @@ -0,0 +1,220 @@ +/* + * 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_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 "../parc_Memory.c" + +LONGBOW_TEST_RUNNER(parc_Memory) +{ + // 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(Static); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_Memory) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_Memory) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcMemory_RoundUpToMultiple); + LONGBOW_RUN_TEST_CASE(Global, parcMemory_RoundUpToCacheLine); + LONGBOW_RUN_TEST_CASE(Global, parcMemory_Allocate); + LONGBOW_RUN_TEST_CASE(Global, parcMemory_AllocateAndClear); + LONGBOW_RUN_TEST_CASE(Global, parcMemory_MemAlign); + LONGBOW_RUN_TEST_CASE(Global, parcMemory_Reallocate); + LONGBOW_RUN_TEST_CASE(Global, parcMemory_StringDuplicate); + LONGBOW_RUN_TEST_CASE(Global, parcMemory_Outstanding); + LONGBOW_RUN_TEST_CASE(Global, parcMemory_SetInterface); + LONGBOW_RUN_TEST_CASE(Global, parcMemory_Format); +} + +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, parcMemory_RoundUpToMultiple) +{ + size_t actual = parcMemory_RoundUpToMultiple(14, 12); + assertTrue((actual % 12) == 0, "Expected %zd to be a multiple of %d", actual, 12); + assertTrue(24 == actual, "Expected 24, actual %zd", actual); + + actual = parcMemory_RoundUpToMultiple(14, 20); + assertTrue((actual % 20) == 0, "Expected %zd to be a multiple of %d", actual, 20); + assertTrue(20 == actual, "Expected 20, actual %zd", actual); + + actual = parcMemory_RoundUpToMultiple(20, 20); + assertTrue((actual % 20) == 0, "Expected %zd to be a multiple of %d", actual, 20); + assertTrue(20 == actual, "Expected 20, actual %zd", actual); + + actual = parcMemory_RoundUpToMultiple(0, 20); + assertTrue((actual % 20) == 0, "Expected %zd to be a multiple of %d", actual, 20); + assertTrue(20 == actual, "Expected 20, actual %zd", actual); + + actual = parcMemory_RoundUpToMultiple(8, 0); + assertTrue(actual == 8, "Expected %d, actual %zd", 8, actual); +} + +LONGBOW_TEST_CASE(Global, parcMemory_RoundUpToCacheLine) +{ + size_t actual = parcMemory_RoundUpToCacheLine(LEVEL1_DCACHE_LINESIZE - 1); + assertTrue((actual % LEVEL1_DCACHE_LINESIZE) == 0, + "Expected %zd to be a multiple of %d", actual, LEVEL1_DCACHE_LINESIZE); +} + +LONGBOW_TEST_CASE(Global, parcMemory_Allocate) +{ + void *pointer; + pointer = parcMemory_Allocate(sizeof(int)); + assertNotNull(pointer, "Expected pointer to not be NULL"); + + parcMemory_Deallocate(&pointer); + assertNull(pointer, "Expected pointer to not be NULL"); +} + +LONGBOW_TEST_CASE(Global, parcMemory_MemAlign) +{ + void *pointer; + int actual = parcMemory_MemAlign(&pointer, sizeof(void *), sizeof(int)); + assertTrue(actual == 0, "Expected successful return value."); + assertNotNull(pointer, "Expected pointer to not be NULL"); + + parcMemory_Deallocate(&pointer); + assertNull(pointer, "Expected pointer to not be NULL"); +} + +LONGBOW_TEST_CASE(Global, parcMemory_Reallocate) +{ + void *pointer; + int actual = parcMemory_MemAlign(&pointer, sizeof(void *), sizeof(int)); + assertTrue(actual == 0, "Expected successful return value."); + + pointer = parcMemory_Reallocate(pointer, sizeof(int) * 2); + assertNotNull(pointer, "Expected pointer to not be NULL"); + + parcMemory_Deallocate(&pointer); + assertNull(pointer, "Expected pointer to not be NULL"); +} + +LONGBOW_TEST_CASE(Global, parcMemory_AllocateAndClear) +{ + void *pointer; + pointer = parcMemory_AllocateAndClear(sizeof(int)); + assertNotNull(pointer, "Expected pointer to not be NULL"); + + for (int i = 0; i < sizeof(int); i++) { + assertTrue(((char *) pointer)[i] == 0, "Expected cell to be zero."); + } + + parcMemory_Deallocate(&pointer); + assertNull(pointer, "Expected pointer to not be NULL"); +} + +LONGBOW_TEST_CASE(Global, parcMemory_StringDuplicate) +{ + char *expected = "Hello"; + + char *actual = parcMemory_StringDuplicate(expected, strlen(expected)); + + assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual); + + parcMemory_Deallocate((void **) &actual); +} + +LONGBOW_TEST_CASE(Global, parcMemory_Outstanding) +{ + void *pointer; + pointer = parcMemory_Allocate(sizeof(int)); + + size_t expected = 1; + size_t actual = parcMemory_Outstanding(); + assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual); + + parcMemory_Deallocate(&pointer); + + expected = 0; + actual = parcMemory_Outstanding(); + assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual); +} + +LONGBOW_TEST_CASE(Global, parcMemory_SetInterface) +{ + const PARCMemoryInterface *old = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + + parcMemory_SetInterface(old); +} + +LONGBOW_TEST_CASE(Global, parcMemory_Format) +{ + char *expected = "Hello World"; + char *actual = parcMemory_Format("Hello %s", "World"); + + assertTrue(strcmp(expected, actual) == 0, + "Expected '%s', actual '%s'", expected, actual); + + parcMemory_Deallocate(&actual); +} + +LONGBOW_TEST_FIXTURE(Static) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Memory); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_Network.c b/libparc/parc/algol/test/test_parc_Network.c new file mode 100755 index 00000000..864fe25d --- /dev/null +++ b/libparc/parc/algol/test/test_parc_Network.c @@ -0,0 +1,668 @@ +/* + * 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 "../parc_Network.c" + +#include <LongBow/unit-test.h> + +#include <stdio.h> + +#include <parc/algol/parc_SafeMemory.h> +#include <parc/testing/parc_ObjectTesting.h> + +#include <sys/un.h> + +LONGBOW_TEST_RUNNER(parc_Networking) +{ + // 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(Local); + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_Networking) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_Networking) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_SockInet4AddressAny); + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_SockInet4Address_BuildString); + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_SockInet6Address_BuildString); + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_BuildString_dashes); + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_BuildString_colons); + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_Inet4Equals); + + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_dashes); + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_colons); + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_dots); + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_ParseLinkAddress_BadScheme); + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_BadLink); + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_BadMixOfDashesAndDots); + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_BadMixOfDotsAndDashes); + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_BadSpecification); + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_ParseInet4Address); + + LONGBOW_RUN_TEST_CASE(Global, parseMAC48Address); + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_ParseMAC48Address_Colons); + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_ParseMAC48Address_Colons_TooShort); + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_ParseMAC48Address_Colons_Garbage); + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_ParseMAC48Address); + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_ParseMAC48Address_TooShort); + + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_SockAddress_ipv4); + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_SockAddress_ipv6); + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_SockAddress_hostname); + + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_IsSocketLocal_PF_LOCAL); + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_IsSocketLocal_PF_INET4); + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_IsSocketLocal_PF_INET6); + LONGBOW_RUN_TEST_CASE(Global, parcNetwork_IsSocketLocal_PF_IPX); +} + +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, parcNetwork_SockInet4AddressAny) +{ + struct sockaddr_in *test_sock = parcNetwork_SockInet4AddressAny(); + + assertNotNull(test_sock, "Expected a not null pointer\n"); + assertTrue(test_sock->sin_family == AF_INET, "Expecting sin_family to be AF_INET\n"); + assertTrue(test_sock->sin_addr.s_addr == INADDR_ANY, "Expecting sin_addr.s_addr to be set to INADDR_ANY\n"); +#if defined(SIN6_LEN) + assertTrue(test_sock->sin_len == sizeof(struct sockaddr_in), "Expecting sockaddr.sin_len to be %zu not %hhu\n", + sizeof(struct sockaddr_in), test_sock->sin_len); +#endif + + parcMemory_Deallocate((void **) &test_sock); +} + +LONGBOW_TEST_CASE(Global, parcNetwork_SockInet4Address_BuildString) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + + struct sockaddr_in *address = parcNetwork_SockInet4Address("127.0.0.1", 1234); +#if defined(SIN6_LEN) + assertTrue(address->sin_len == sizeof(struct sockaddr_in), "Expecting sockaddr.sin_len to be %zu not %hhu\n", + sizeof(struct sockaddr_in), address->sin_len); +#endif + parcNetwork_SockInet4Address_BuildString(address, composer); + + char *expected = "inet4://127.0.0.1:1234"; + + PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); + char *actual = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + + assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual); + + parcMemory_Deallocate((void **) &actual); + parcMemory_Deallocate((void **) &address); + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, parcNetwork_SockInet6Address_BuildString) +{ + struct sockaddr_in6 *address = parcNetwork_SockInet6Address("2001:720:1500:1::a100", 1234, 0, 1); +#if defined(SIN6_LEN) + assertTrue(address->sin6_len == sizeof(struct sockaddr_in6), "Expecting sockaddr.sin6_len to be %zu not %hhu\n", + sizeof(struct sockaddr_in6), address->sin6_len); +#endif + + PARCBufferComposer *composer = parcBufferComposer_Create(); + parcNetwork_SockInet6Address_BuildString(address, composer); + + char *expected = "inet6://[2001:720:1500:1::a100%1]:1234"; + + PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); + char *actual = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + + assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual); + + parcMemory_Deallocate((void **) &actual); + parcMemory_Deallocate((void **) &address); + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, parcNetwork_LinkAddress_BuildString_dashes) +{ + char *expected = "link://01-23-45-67-89-ab"; + + PARCBuffer *address = parcNetwork_ParseLinkAddress(expected); + + PARCBufferComposer *composer = parcBufferComposer_Create(); + + parcNetwork_LinkAddress_BuildString((unsigned char *) parcBuffer_Overlay(address, 0), parcBuffer_Remaining(address), composer); + + PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); + char *actual = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + + assertTrue(strcmp(expected, actual) == 0, + "Expected '%s', actual '%s'", expected, actual); + + parcMemory_Deallocate((void **) &actual); + parcBufferComposer_Release(&composer); + parcBuffer_Release(&address); +} + +LONGBOW_TEST_CASE(Global, parcNetwork_LinkAddress_BuildString_colons) +{ + char *expected = "link://01-23-45-67-89-ab"; + + PARCBuffer *address = parcNetwork_ParseLinkAddress("link://01:23:45:67:89:ab"); + + PARCBufferComposer *composer = parcBufferComposer_Create(); + parcNetwork_LinkAddress_BuildString((unsigned char *) parcBuffer_Overlay(address, 0), parcBuffer_Remaining(address), composer); + + PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); + char *actual = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + + assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual); + + parcMemory_Deallocate((void **) &actual); + parcBufferComposer_Release(&composer); + parcBuffer_Release(&address); +} + +LONGBOW_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_dashes) +{ + char *expected = "link://01-23-45-67-89-ab"; + PARCBuffer *address = parcNetwork_ParseLinkAddress(expected); + parcBuffer_Flip(address); + + PARCBuffer *e = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6); + + parcBuffer_SetPosition(address, 0); + parcBuffer_SetLimit(address, 6); + + parcBuffer_SetPosition(e, 0); + parcBuffer_SetLimit(e, 6); + + assertTrue(parcBuffer_Equals(address, e), + "Expected result failed."); + + parcBuffer_Release(&e); + parcBuffer_Release(&address); +} + +LONGBOW_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_colons) +{ + char *expected = "link://01:23:45:67:89:ab"; + PARCBuffer *address = parcNetwork_ParseLinkAddress(expected); + + PARCBuffer *e = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6); + + parcBuffer_SetPosition(address, 0); + parcBuffer_SetPosition(e, 0); + parcBuffer_SetLimit(address, 6); + parcBuffer_SetLimit(e, 6); + + assertTrue(parcBuffer_Equals(address, e), + "Expected result failed."); + + parcBuffer_Release(&e); + parcBuffer_Release(&address); +} + +LONGBOW_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_dots) +{ + char *expected = "link://0123.4567.89ab"; + PARCBuffer *address = parcNetwork_ParseLinkAddress(expected); + + PARCBuffer *e = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6); + + parcBuffer_SetPosition(address, 0); + parcBuffer_SetPosition(e, 0); + parcBuffer_SetLimit(address, 6); + parcBuffer_SetLimit(e, 6); + + assertTrue(parcBuffer_Equals(address, e), + "Expected result failed."); + + parcBuffer_Release(&e); + parcBuffer_Release(&address); +} + +LONGBOW_TEST_CASE_EXPECTS(Global, parcNetwork_ParseLinkAddress_BadScheme, .event = &LongBowTrapIllegalValue) +{ + char *expected = "asdf://"; + parcNetwork_ParseLinkAddress(expected); +} + +LONGBOW_TEST_CASE_EXPECTS(Global, parcNetwork_LinkAddress_Parse_BadLink, .event = &LongBowTrapIllegalValue) +{ + char *expected = "link://"; + parcNetwork_ParseLinkAddress(expected); + printf("Hello\n"); +} + +LONGBOW_TEST_CASE_EXPECTS(Global, parcNetwork_LinkAddress_Parse_BadSpecification, .event = &LongBowTrapIllegalValue) +{ + char *expected = "link://a"; + parcNetwork_ParseLinkAddress(expected); +} + +LONGBOW_TEST_CASE_EXPECTS(Global, parcNetwork_LinkAddress_Parse_BadMixOfDashesAndDots, .event = &LongBowTrapIllegalValue) +{ + char *expected = "link://01-23-45.6789ab"; + parcNetwork_ParseLinkAddress(expected); +} + +LONGBOW_TEST_CASE_EXPECTS(Global, parcNetwork_LinkAddress_Parse_BadMixOfDotsAndDashes, .event = &LongBowTrapIllegalValue) +{ + char *expected = "link://012345.67-89-ab"; + parcNetwork_ParseLinkAddress(expected); +} + +LONGBOW_TEST_CASE(Global, parseMAC48Address) +{ + PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6); + + PARCBuffer *buffer = parcBuffer_Allocate(7); + bool actual = parcNetwork_ParseMAC48Address("01-23-45-67-89-ab", buffer); + assertTrue(actual, "Expected parcNetwork_ParseMAC48Address() to return true"); + + parcBuffer_Flip(buffer); + + assertTrue(parcBuffer_Equals(expected, buffer), "Expected buffer contents failed."); + + parcBuffer_Release(&expected); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcNetwork_ParseMAC48Address_Colons) +{ + PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6); + + PARCBuffer *buffer = parcBuffer_Allocate(7); + bool actual = parcNetwork_ParseMAC48Address("01:23:45:67:89:ab", buffer); + assertTrue(actual, "Expected parcNetwork_ParseMAC48Address() to return true"); + parcBuffer_Flip(buffer); + + assertTrue(parcBuffer_Equals(expected, buffer), "Expected buffer contents failed."); + + parcBuffer_Release(&expected); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcNetwork_ParseMAC48Address_Colons_TooShort) +{ + PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6); + + PARCBuffer *buffer = parcBuffer_Allocate(7); + bool actual = parcNetwork_ParseMAC48Address("01:23:45:67:89", buffer); + assertFalse(actual, "Expected parcNetwork_ParseMAC48Address() to return false"); + assertTrue(parcBuffer_Position(buffer) == 0, "Expected buffer to be unmodified."); + + parcBuffer_Release(&expected); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcNetwork_ParseMAC48Address_Colons_Garbage) +{ + PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6); + + PARCBuffer *buffer = parcBuffer_Allocate(7); + bool actual = parcNetwork_ParseMAC48Address("0x:23:45:67:89:ab", buffer); + assertFalse(actual, "Expected parcNetwork_ParseMAC48Address() to return false"); + assertTrue(parcBuffer_Position(buffer) == 0, "Expected the PARCBuffer to be unchanged."); + + parcBuffer_Release(&expected); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcNetwork_ParseMAC48Address) +{ + PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6); + + PARCBuffer *buffer = parcBuffer_Allocate(7); + bool actual = parcNetwork_ParseMAC48Address("0123.4567.89ab", buffer); + assertTrue(actual, "Expected _parseLinkAddressDot() to return true"); + parcBuffer_Flip(buffer); + + assertTrue(parcBuffer_Equals(expected, buffer), "Expected buffer contents failed."); + + parcBuffer_Release(&expected); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcNetwork_ParseMAC48Address_TooShort) +{ + PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6); + + PARCBuffer *buffer = parcBuffer_Allocate(7); + bool actual = parcNetwork_ParseMAC48Address("0123.4567", buffer); + assertFalse(actual, "Expected parcNetwork_ParseMAC48Address() to return false"); + assertTrue(parcBuffer_Position(buffer) == 0, "Expected the PARCBuffer to be unchanged."); + + parcBuffer_Release(&expected); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcNetwork_ParseInet4Address) +{ + struct sockaddr_in *address = parcNetwork_SockInet4Address("127.0.0.1", 1234); + + PARCBufferComposer *composer = parcNetwork_SockInet4Address_BuildString(address, parcBufferComposer_Create()); + + PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); + char *addressURI = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + + struct sockaddr_in *actual = parcNetwork_ParseInet4Address(addressURI); + + assertTrue(parcNetwork_Inet4Equals(address, actual), + "Expected Addresses are not equal"); + + parcMemory_Deallocate((void **) &actual); + parcMemory_Deallocate((void **) &addressURI); + parcBufferComposer_Release(&composer); + parcMemory_Deallocate((void **) &address); +} + +LONGBOW_TEST_CASE(Global, parcNetwork_Inet4Equals) +{ + struct sockaddr_in *x = parcNetwork_SockInet4Address("127.0.0.1", 1234); + struct sockaddr_in *y = parcNetwork_SockInet4Address("127.0.0.1", 1234); + struct sockaddr_in *z = parcNetwork_SockInet4Address("127.0.0.1", 1234); + struct sockaddr_in *u1 = parcNetwork_SockInet4Address("127.0.0.2", 1234); + struct sockaddr_in *u2 = parcNetwork_SockInet4Address("127.0.0.1", 4567); + + parcObjectTesting_AssertEqualsFunction(parcNetwork_Inet4Equals, x, y, z, u1, u2); + + parcMemory_Deallocate((void **) &x); + parcMemory_Deallocate((void **) &y); + parcMemory_Deallocate((void **) &z); + parcMemory_Deallocate((void **) &u1); + parcMemory_Deallocate((void **) &u2); +} + +LONGBOW_TEST_CASE(Global, parcNetwork_SockAddress_ipv4) +{ + const char *ipv4 = "1.1.1.1"; + unsigned short port = 5959; + + struct sockaddr_in truth = { + .sin_family = PF_INET, + .sin_port = htons(port), + .sin_addr.s_addr = htonl(0x01010101) + }; + + struct sockaddr_in *test = (struct sockaddr_in *) parcNetwork_SockAddress(ipv4, port); + assertNotNull(test, "Got null address for %s port %u", ipv4, port); + assertTrue(truth.sin_family == test->sin_family, "wrong family, expected %d got %d", truth.sin_family, test->sin_family); + assertTrue(truth.sin_port == test->sin_port, "wrong port, expected %u got %u", truth.sin_port, test->sin_port); + + assertTrue(memcmp(&truth.sin_addr, &test->sin_addr, sizeof(struct in_addr)) == 0, "struct in_addr did not compare"); + parcMemory_Deallocate((void **) &test); +} + +LONGBOW_TEST_CASE(Global, parcNetwork_SockAddress_ipv6) +{ + const char *ipv6 = "fe80::aa20:66ff:fe00:314a"; + uint8_t truth_addr[16] = { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0xaa, 0x20, 0x66, 0xff, 0xfe, 0x00, 0x31, 0x4a }; + + unsigned short port = 5959; + + struct sockaddr_in6 truth = { + .sin6_family = PF_INET6, + .sin6_port = htons(port) + }; + + memcpy(&truth.sin6_addr, truth_addr, sizeof(truth.sin6_addr)); + + + struct sockaddr_in6 *test = (struct sockaddr_in6 *) parcNetwork_SockAddress(ipv6, port); + if (test == NULL) { + testSkip("IPv6 is not supported in the runtime environment."); + } + assertTrue(truth.sin6_family == test->sin6_family, "wrong family, expected %d got %d", truth.sin6_family, test->sin6_family); + assertTrue(truth.sin6_port == test->sin6_port, "wrong port, expected %u got %u", truth.sin6_port, test->sin6_port); + + assertTrue(memcmp(&truth.sin6_addr, &test->sin6_addr, sizeof(struct in6_addr)) == 0, "struct in_addr did not compare"); + parcMemory_Deallocate((void **) &test); +} + +LONGBOW_TEST_CASE(Global, parcNetwork_SockAddress_hostname) +{ + const char *name = "localhost"; + unsigned short port = 5959; + + struct sockaddr *test = parcNetwork_SockAddress(name, port); + assertNotNull(test, "Got null looking up '%s'", name); + parcMemory_Deallocate((void **) &test); +} + +LONGBOW_TEST_CASE(Global, parcNetwork_IsSocketLocal_PF_LOCAL) +{ + struct sockaddr_un name; + name.sun_family = PF_LOCAL; + + bool isLocal = parcNetwork_IsSocketLocal((struct sockaddr *) &name); + assertTrue(isLocal, "PF_LOCAL address did not return as local"); +} + +LONGBOW_TEST_CASE(Global, parcNetwork_IsSocketLocal_PF_IPX) +{ + struct sockaddr_un name; + name.sun_family = PF_IPX; + + bool isLocal = parcNetwork_IsSocketLocal((struct sockaddr *) &name); + assertFalse(isLocal, "Expected parcNetwork_IsSocketLocal(PF_PUP) to return false"); +} + +LONGBOW_TEST_CASE(Global, parcNetwork_IsSocketLocal_PF_INET4) +{ + struct sockaddr *s = parcNetwork_SockAddress("127.1.1.1", 5900); + bool isLoopback = parcNetwork_IsSocketLocal(s); + assertTrue(isLoopback, "127.1.1.1 should be called loopback"); + parcMemory_Deallocate((void **) &s); +} + +LONGBOW_TEST_CASE(Global, parcNetwork_IsSocketLocal_PF_INET6) +{ + struct sockaddr *s = parcNetwork_SockAddress("::1", 5900); + bool isLoopback = parcNetwork_IsSocketLocal(s); + assertTrue(isLoopback, "::1 should be called loopback"); + parcMemory_Deallocate((void **) &s); +} + + +// ======================================================================= + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, parcNetwork_IsInet6Local_True); + LONGBOW_RUN_TEST_CASE(Local, parcNetwork_IsInet6Local_False); + LONGBOW_RUN_TEST_CASE(Local, parcNetwork_IsInet4Local_True); + LONGBOW_RUN_TEST_CASE(Local, parcNetwork_IsInet4Local_False); + + LONGBOW_RUN_TEST_CASE(Local, _parseMAC48AddressDashOrColon); + LONGBOW_RUN_TEST_CASE(Local, _parseMAC48AddressDashOrColon_Colons); + LONGBOW_RUN_TEST_CASE(Local, _parseMAC48AddressDot); + LONGBOW_RUN_TEST_CASE(Local, _parseMAC48AddressDot_TooShort); + LONGBOW_RUN_TEST_CASE(Local, _parseMAC48AddressDashOrColon_Colons_TooShort); + LONGBOW_RUN_TEST_CASE(Local, _parseMAC48AddressDashOrColon_Colons_Garbage); +} + +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, parcNetwork_IsInet6Local_True) +{ + struct sockaddr *s = parcNetwork_SockAddress("::1", 5900); + + bool isLoopback = _isInet6Loopback((struct sockaddr_in6 *) s); + assertTrue(isLoopback, "::1 should be called loopback"); + parcMemory_Deallocate((void **) &s); +} + +LONGBOW_TEST_CASE(Local, parcNetwork_IsInet6Local_False) +{ + struct sockaddr *s = parcNetwork_SockAddress("fe80::aa20:66ff:fe00:1", 5900); + + bool isLoopback = _isInet6Loopback((struct sockaddr_in6 *) s); + assertFalse(isLoopback, "fe80::aa20:66ff:fe00:1 should not be called loopback"); + parcMemory_Deallocate((void **) &s); +} + +LONGBOW_TEST_CASE(Local, parcNetwork_IsInet4Local_True) +{ + struct sockaddr *s = parcNetwork_SockAddress("127.1.1.1", 5900); + + bool isLoopback = _isInet4Loopback((struct sockaddr_in *) s); + assertTrue(isLoopback, "127.1.1.1 should be called loopback"); + parcMemory_Deallocate((void **) &s); +} + +LONGBOW_TEST_CASE(Local, parcNetwork_IsInet4Local_False) +{ + struct sockaddr *s = parcNetwork_SockAddress("13.1.1.1", 5900); + + bool isLoopback = _isInet4Loopback((struct sockaddr_in *) s); + assertFalse(isLoopback, "13.1.1.1 should not be called loopback"); + parcMemory_Deallocate((void **) &s); +} + +LONGBOW_TEST_CASE(Local, _parseMAC48AddressDashOrColon) +{ + PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6); + + PARCBuffer *buffer = parcBuffer_Allocate(7); + PARCBuffer *actual = _parseMAC48AddressDashOrColon("01-23-45-67-89-ab", buffer); + assertNotNull(actual, "Expected _parseLinkAddressDashOrColon() to return non-NULL value"); + parcBuffer_Flip(actual); + + assertTrue(parcBuffer_Equals(expected, actual), "Expected buffer contents failed."); + + parcBuffer_Release(&expected); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Local, _parseMAC48AddressDashOrColon_Colons) +{ + PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6); + + PARCBuffer *buffer = parcBuffer_Allocate(7); + PARCBuffer *actual = _parseMAC48AddressDashOrColon("01:23:45:67:89:ab", buffer); + assertNotNull(actual, "Expected _parseLinkAddressDashOrColon() to return non-NULL value"); + parcBuffer_Flip(actual); + + assertTrue(parcBuffer_Equals(expected, actual), "Expected buffer contents failed."); + + parcBuffer_Release(&expected); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Local, _parseMAC48AddressDashOrColon_Colons_TooShort) +{ + PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6); + + PARCBuffer *buffer = parcBuffer_Allocate(7); + PARCBuffer *actual = _parseMAC48AddressDashOrColon("01:23:45:67:89", buffer); + assertNull(actual, "Expected _parseLinkAddressDashOrColon() to return NULL value"); + + parcBuffer_Release(&expected); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Local, _parseMAC48AddressDashOrColon_Colons_Garbage) +{ + PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6); + + PARCBuffer *buffer = parcBuffer_Allocate(7); + PARCBuffer *actual = _parseMAC48AddressDashOrColon("0x:23:45:67:89:ab", buffer); + assertNull(actual, "Expected _parseLinkAddressDashOrColon() to return NULL value"); + assertTrue(parcBuffer_Position(buffer) == 0, "Expected the PARCBuffer to be unchanged."); + + parcBuffer_Release(&expected); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Local, _parseMAC48AddressDot) +{ + PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6); + + PARCBuffer *buffer = parcBuffer_Allocate(7); + PARCBuffer *actual = _parseMAC48AddressDot("0123.4567.89ab", buffer); + assertNotNull(actual, "Expected _parseLinkAddressDot() to return non-NULL value"); + parcBuffer_Flip(actual); + + assertTrue(parcBuffer_Equals(expected, actual), "Expected buffer contents failed."); + + parcBuffer_Release(&expected); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Local, _parseMAC48AddressDot_TooShort) +{ + PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6); + + PARCBuffer *buffer = parcBuffer_Allocate(7); + PARCBuffer *actual = _parseMAC48AddressDot("0123.4567", buffer); + assertNull(actual, "Expected _parseLinkAddressDot() to return NULL value"); + + parcBuffer_Release(&expected); + parcBuffer_Release(&buffer); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Networking); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_Object.c b/libparc/parc/algol/test/test_parc_Object.c new file mode 100755 index 00000000..687654fe --- /dev/null +++ b/libparc/parc/algol/test/test_parc_Object.c @@ -0,0 +1,1580 @@ +/* + * 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 "../parc_Object.c" + +#include <inttypes.h> +#include <sys/time.h> + +#include <LongBow/unit-test.h> + +#include <parc/testing/parc_ObjectTesting.h> +#include <parc/testing/parc_MemoryTesting.h> + +#include <parc/algol/parc_SafeMemory.h> +#include <parc/algol/parc_StdlibMemory.h> + +typedef struct { + int calledCount; + int val; +} _dummy_object; + +typedef _dummy_object _DummyObject; + +static void +_dummy_Destroy(_DummyObject **obj __attribute__((unused))) +{ +} + +static _DummyObject * +_dummy_Copy(const _DummyObject *obj); + + +static bool +_dummy_Equals(const _DummyObject *x, const _DummyObject *y) +{ + const _DummyObject *dummy1 = x; + const _DummyObject *dummy2 = y; + return (dummy1->calledCount == dummy2->calledCount); +} + +static int +_dummy_Compare(const _DummyObject *x, const _DummyObject *y) +{ + const _DummyObject *dummy1 = x; + const _DummyObject *dummy2 = y; + if (dummy1->calledCount == dummy2->calledCount) { + return 0; + } else if (dummy1->calledCount < dummy2->calledCount) { + return -1; + } else { + return 1; + } +} + +static uint32_t +_dummy_HashCode(const _DummyObject *obj) +{ + _DummyObject *dummy = (_DummyObject *) obj; + dummy->calledCount++; + return 1337; +} + +static char * +_dummy_ToString(const _DummyObject *x __attribute__((unused))) +{ + char *str = (char *) parcMemory_Allocate(6); + char *test = "dummy"; + sprintf(str, "%s", test); + return str; +} + +static PARCJSON * +_dummy_ToJSON(const _DummyObject *x __attribute__((unused))) +{ + PARCJSON *json = parcJSON_ParseString("{ \"type\" : \"dummy\" }"); + return json; +} + +parcObject_Override(_DummyObject, PARCObject, + .destroy = (PARCObjectDestroy *) _dummy_Destroy, + .copy = (PARCObjectCopy *) _dummy_Copy, + .toString = (PARCObjectToString *) _dummy_ToString, + .equals = (PARCObjectEquals *) _dummy_Equals, + .compare = (PARCObjectCompare *) _dummy_Compare, + .hashCode = (PARCObjectHashCode *) _dummy_HashCode, + .toJSON = (PARCObjectToJSON *) _dummy_ToJSON); + +static _DummyObject * +_dummy_Copy(const _DummyObject *obj) +{ + _DummyObject *newDummy = parcObject_CreateInstance(_DummyObject); + const _DummyObject *dummy = obj; + newDummy->calledCount = dummy->calledCount; + return newDummy; +} + +typedef _dummy_object _DummyObjectNoHash; +parcObject_ExtendPARCObject(_DummyObjectNoHash, + _dummy_Destroy, + _dummy_Copy, + _dummy_ToString, + _dummy_Equals, + _dummy_Compare, + NULL, + _dummy_ToJSON); + +static bool +_meta_destructor_true(PARCObject **objPtr) +{ + return true; +} + +static bool +_meta_destructor_false(PARCObject **objPtr) +{ + (*objPtr) = NULL; + return false; +} + +static PARCObject * +_meta_copy(const PARCObject *ptr) +{ + _DummyObject *d = parcMemory_AllocateAndClear(sizeof(_DummyObject)); + _DummyObject *xx = (_DummyObject *) ptr; + d->val = xx->val; + return d; +} + +static bool +_meta_equals(const PARCObject *x, const PARCObject *y) +{ + _DummyObject *xx = (_DummyObject *) x; + _DummyObject *yy = (_DummyObject *) y; + return (xx->val == yy->val); +} + +static int +_meta_compare(const PARCObject *x, const PARCObject *y) +{ + _DummyObject *xx = (_DummyObject *) x; + _DummyObject *yy = (_DummyObject *) y; + + if (xx->val == yy->val) { + return 0; + } else if (xx->val < yy->val) { + return -1; + } else { + return 1; + } +} + +static PARCHashCode +_meta_hashCode(const PARCObject *ptr) +{ + _DummyObject *xx = (_DummyObject *) ptr; + return xx->val; +} + +static char * +_meta_toString(const PARCObject *ptr) +{ + _DummyObject *xx = (_DummyObject *) ptr; + + char *result; + parcMemory_MemAlign((void **) &result, sizeof(void *), sizeof(char)); + assertNotNull(result, "parcMemory_Allocate returned NULL"); + + char *p = result; + sprintf(result, "%d", xx->val); + + return p; +} + +static PARCJSON * +_meta_toJson(const PARCObject *ptr) +{ + _DummyObject *xx = (_DummyObject *) ptr; + + PARCJSON *json = parcJSON_Create(); + parcJSON_AddInteger(json, "value", xx->val); + + return json; +} + +static const PARCMemoryInterface *_originalMemoryProvider; + +LONGBOW_TEST_RUNNER(parcObject) +{ + LONGBOW_RUN_TEST_FIXTURE(Performance); + LONGBOW_RUN_TEST_FIXTURE(PARCObjectDescriptor); + LONGBOW_RUN_TEST_FIXTURE(Static); + LONGBOW_RUN_TEST_FIXTURE(StaticObjects); + LONGBOW_RUN_TEST_FIXTURE(Meta); + LONGBOW_RUN_TEST_FIXTURE(AcquireRelease); + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Subclasses); + LONGBOW_RUN_TEST_FIXTURE(Fail); + LONGBOW_RUN_TEST_FIXTURE(Locking); + LONGBOW_RUN_TEST_FIXTURE(WaitNotify); + LONGBOW_RUN_TEST_FIXTURE(Synchronization); +} + +LONGBOW_TEST_RUNNER_SETUP(parcObject) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(parcObject) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Static) +{ + LONGBOW_RUN_TEST_CASE(Static, _objectHeaderIsValid); + LONGBOW_RUN_TEST_CASE(Static, _parcObject_PrefixLength); +} + +LONGBOW_TEST_FIXTURE_SETUP(Static) +{ + _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Static) +{ + parcMemory_SetInterface(_originalMemoryProvider); + return LONGBOW_STATUS_SUCCEEDED; +} + +struct timeval _testObject; + +parcObject_Override(_testObject, PARCObject); + +LONGBOW_TEST_CASE(Static, _objectHeaderIsValid) +{ + PARCObject *object = parcObject_CreateInstanceImpl(&_testObject_Descriptor); + + _PARCObjectHeader *header = _parcObject_Header(object); + + assertTrue(_parcObjectHeader_IsValid(header, object), "Expected _parcObject_HeaderHeaderIsValid to be valid"); + + parcObject_Release(&object); +} + +LONGBOW_TEST_CASE(Static, _parcObject_PrefixLength) +{ + // Test that the result is a multiple of the alignment value and greater than the size of _PARCObjectHeader. + + // Compute the power of 2 value of sizeof(void *) + unsigned int v = sizeof(void *); + unsigned int r = 0; // r will be lg(v) + + while (v >>= 1) { + r++; + } + PARCObjectDescriptor descriptor; + + for (int i = r; i < 20; i++) { + descriptor.objectAlignment = 1 << i; + size_t actual = _parcObject_PrefixLength(&descriptor); + assertTrue((actual & (descriptor.objectAlignment - 1)) == 0, + "Alignment needs to be a multiple of %u", descriptor.objectAlignment); + } +} + +LONGBOW_TEST_FIXTURE(AcquireRelease) +{ + LONGBOW_RUN_TEST_CASE(AcquireRelease, parcObject_Acquire); + LONGBOW_RUN_TEST_CASE(AcquireRelease, parcObject_Release); +// LONGBOW_RUN_TEST_CASE(AcquireRelease, parcObject_Acquire_Invalid); +} + +LONGBOW_TEST_FIXTURE_SETUP(AcquireRelease) +{ + _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(AcquireRelease) +{ + parcSafeMemory_ReportAllocation(STDOUT_FILENO); + parcMemory_SetInterface(_originalMemoryProvider); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(AcquireRelease, parcObject_Acquire) +{ + struct timeval *expected = parcObject_CreateInstanceImpl(&_testObject_Descriptor); + + parcObjectTesting_AssertAcquireReleaseContract(parcObject_Acquire, expected); + parcObject_Release((void **) &expected); +} + +LONGBOW_TEST_CASE(AcquireRelease, parcObject_Release) +{ + struct timeval *time = parcObject_CreateInstanceImpl(&_testObject_Descriptor); + parcObject_AssertValid(time); + + time->tv_sec = 1; + time->tv_usec = 2; + + PARCReferenceCount count = parcObject_Release((PARCObject **) &time); + assertTrue(count == 0, "Expected reference count to be zero"); + assertTrue(time == 0, "Expected memory pointer to be NULL after destroy."); +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcObject_Create); +// LONGBOW_RUN_TEST_CASE(Global, parcObject_CreateAndClear); + LONGBOW_RUN_TEST_CASE(Global, parcObject_IsValid); + LONGBOW_RUN_TEST_CASE(Global, parcObject_IsValid_NotValid); + LONGBOW_RUN_TEST_CASE(Global, parcObject_IsInstanceOf); + LONGBOW_RUN_TEST_CASE(Global, parcObject_Copy_Default); + LONGBOW_RUN_TEST_CASE(Global, parcObject_Copy); + LONGBOW_RUN_TEST_CASE(Global, parcObject_Release); + LONGBOW_RUN_TEST_CASE(Global, parcObject_Compare_Default); + LONGBOW_RUN_TEST_CASE(Global, parcObject_Compare_NoOverride); + LONGBOW_RUN_TEST_CASE(Global, parcObject_Compare); + LONGBOW_RUN_TEST_CASE(Global, parcObject_Equals_Default); + LONGBOW_RUN_TEST_CASE(Global, parcObject_Equals_NoOverride); + LONGBOW_RUN_TEST_CASE(Global, parcObject_Equals); + LONGBOW_RUN_TEST_CASE(Global, parcObject_HashCode_Default); + LONGBOW_RUN_TEST_CASE(Global, parcObject_HashCode_NoOverride); + LONGBOW_RUN_TEST_CASE(Global, parcObject_HashCode); + LONGBOW_RUN_TEST_CASE(Global, parcObject_ToString_Default); + LONGBOW_RUN_TEST_CASE(Global, parcObject_ToString_NoOverride); + LONGBOW_RUN_TEST_CASE(Global, parcObject_ToString); + LONGBOW_RUN_TEST_CASE(Global, parcObject_ToJSON_Default); + LONGBOW_RUN_TEST_CASE(Global, parcObject_ToJSON_NoOverride); + LONGBOW_RUN_TEST_CASE(Global, parcObject_ToJSON); + LONGBOW_RUN_TEST_CASE(Global, parcObject_GetReferenceCount); + LONGBOW_RUN_TEST_CASE(Global, parcObject_Display_Default); + LONGBOW_RUN_TEST_CASE(Global, parcObject_Display_NoOverride); + LONGBOW_RUN_TEST_CASE(Global, parcObject_Display); + LONGBOW_RUN_TEST_CASE(Global, parcObject_GetDescriptor); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + + parcMemory_SetInterface(_originalMemoryProvider); + + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, parcObject_Release) +{ + struct timeval *time = parcObject_CreateInstanceImpl(&_testObject_Descriptor); + parcObject_AssertValid(time); + + time->tv_sec = 1; + time->tv_usec = 2; + + PARCReferenceCount count = parcObject_Release((PARCObject **) &time); + assertTrue(count == 0, "Expected reference count to be zero"); + assertTrue(time == 0, "Expected memory pointer to be NULL after destroy."); +} + +LONGBOW_TEST_CASE(Global, parcObject_Create) +{ + struct timeval *time = parcObject_CreateInstanceImpl(&_testObject_Descriptor); + parcObject_AssertValid(time); + + time->tv_sec = 1; + time->tv_usec = 2; + + PARCReferenceCount count = parcObject_Release((PARCObject **) &time); + assertTrue(count == 0, "Expected reference count to be zero"); + assertTrue(time == 0, "Expected memory pointer to be NULL after destroy."); +} + +//LONGBOW_TEST_CASE(Global, parcObject_CreateAndClear) +//{ +// struct timeval *time = parcObject_CreateAndClear(struct timeval); +// parcObject_AssertValid(time); +// +// time->tv_sec = 1; +// time->tv_usec = 2; +// +// PARCReferenceCount count = parcObject_Release((PARCObject **) &time); +// assertTrue(count == 0, "Expected reference count to be zero"); +// assertTrue(time == 0, "Expected memory pointer to be NULL after destroy."); +//} + +LONGBOW_TEST_CASE(Global, parcObject_IsValid) +{ + PARCObject *object = parcObject_CreateInstanceImpl(&_testObject_Descriptor); + assertTrue(parcObject_IsValid(object), "Expected valid PARCObject"); + + parcObject_Release(&object); +} + +LONGBOW_TEST_CASE(Global, parcObject_IsInstanceOf) +{ + _DummyObject *dummy1 = parcObject_CreateInstance(_DummyObject); + assertTrue(parcObject_IsInstanceOf(dummy1, &PARCObject_Descriptor), + "Expected _DummyObject to be an instance of PARCObject"); + + parcObject_Release((PARCObject **) &dummy1); +} + +LONGBOW_TEST_CASE(Global, parcObject_IsValid_NotValid) +{ + PARCObject *object = parcObject_CreateInstanceImpl(&_testObject_Descriptor); + PARCObject *alias = object; + parcObject_Release(&object); + assertFalse(parcObject_IsValid(object), "Expected invalid PARCObject"); + assertFalse(parcObject_IsValid(alias), "Expected invalid PARCObject"); +} + +LONGBOW_TEST_CASE(Global, parcObject_Copy_Default) +{ + struct timeval *time = parcObject_CreateInstanceImpl(&_testObject_Descriptor); + parcObject_AssertValid(time); + + time->tv_sec = 1; + time->tv_usec = 2; + + struct timeval *copy = parcObject_Copy(time); + + parcObject_AssertValid(copy); + + assertTrue(copy->tv_sec == 1, "Expected tv_sec to equal 1"); + assertTrue(copy->tv_usec == 2, "Expected tv_usec to equal 2"); + + PARCReferenceCount count = parcObject_Release((PARCObject **) ©); + assertTrue(count == 0, "Expected reference count to be zero"); + assertTrue(copy == 0, "Expected memory pointer to be NULL after destroy."); + + parcObject_Release((PARCObject *) &time); +} + +LONGBOW_TEST_CASE(Global, parcObject_Copy) +{ + _DummyObject *dummy1 = parcObject_CreateInstance(_DummyObject); + dummy1->calledCount = 100; + + _DummyObject *dummy2 = parcObject_Copy(dummy1); + + assertTrue(dummy2->calledCount == dummy1->calledCount, + "Expected called counts to be the same. Got %d, expected %d.", dummy1->calledCount, dummy2->calledCount); + + parcObject_Release((PARCObject **) &dummy1); + parcObject_Release((PARCObject **) &dummy2); +} + +LONGBOW_TEST_CASE(Global, parcObject_Compare_Default) +{ + struct timeval *time1 = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor); + parcObject_AssertValid(time1); + + time1->tv_sec = 1; + time1->tv_usec = 2; + + struct timeval *time2 = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor); + parcObject_AssertValid(time2); + + time2->tv_sec = 1; + time2->tv_usec = 2; + + int compareResult = parcObject_Compare(time1, time2); + assertTrue(compareResult == 0, "Expected objects to compare equal. Comparison result: %d", compareResult); + compareResult = parcObject_Compare(time1, time1); + assertTrue(compareResult == 0, "Expected same object to be equal since they have identical pointer addresses. Comparison result: %d", compareResult); + + parcObject_Release((PARCObject *) &time1); + parcObject_Release((PARCObject *) &time2); +} + +LONGBOW_TEST_CASE(Global, parcObject_Compare_NoOverride) +{ + const PARCObjectDescriptor *descriptor = + parcObjectDescriptor_Create("override", + sizeof(struct timeval), sizeof(void*), + true, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &PARCObject_Descriptor, NULL); + struct timeval *time1 = parcObject_CreateAndClearInstanceImpl(descriptor); + parcObject_AssertValid(time1); + + time1->tv_sec = 1; + time1->tv_usec = 2; + + struct timeval *time2 = parcObject_CreateAndClearInstanceImpl(descriptor); + parcObject_AssertValid(time2); + + time2->tv_sec = 1; + time2->tv_usec = 2; + + int compareResult = parcObject_Compare(time1, time2); + assertTrue(compareResult == 0, "Expected objects to compare equal. Comparison result: %d", compareResult); + compareResult = parcObject_Compare(time1, time1); + assertTrue(compareResult == 0, "Expected same object to be equal since they have identical pointer addresses. Comparison result: %d", compareResult); + + parcObject_Release((PARCObject *) &time1); + parcObject_Release((PARCObject *) &time2); + parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &descriptor); +} + +LONGBOW_TEST_CASE(Global, parcObject_Compare) +{ + _DummyObject *value = parcObject_CreateAndClearInstance(_DummyObject); + _DummyObject *equality[2]; + equality[0] = parcObject_CreateAndClearInstance(_DummyObject); + equality[1] = NULL; + _DummyObject *lesser[2]; + lesser[0] = parcObject_CreateAndClearInstance(_DummyObject); + lesser[1] = NULL; + + _DummyObject *greater[2]; + greater[0] = parcObject_CreateAndClearInstance(_DummyObject); + greater[1] = NULL; + + value->calledCount = 50; + equality[0]->calledCount = 50; + lesser[0]->calledCount = 10; + greater[0]->calledCount = 80; + + parcObjectTesting_AssertCompareTo(parcObject_Compare, value, equality, lesser, greater); + + parcObject_Release((void **) &value); + parcObject_Release((void **) &equality[0]); + parcObject_Release((void **) &lesser[0]); + parcObject_Release((void **) &greater[0]); +} + +LONGBOW_TEST_CASE(Global, parcObject_Equals_Default) +{ + struct timeval *x = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor); + memset(x, 0, sizeof(struct timeval)); + x->tv_sec = 1; + x->tv_usec = 2; + + struct timeval *y = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor); + memset(y, 0, sizeof(struct timeval)); + y->tv_sec = 1; + y->tv_usec = 2; + + assertTrue(parcObject_Equals(x, y), "Expected equality"); + + struct timeval *z = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor); + z->tv_sec = 1; + z->tv_usec = 2; + + struct timeval *unequal1 = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor); + unequal1->tv_sec = 1; + unequal1->tv_usec = 1; + + struct timeval *unequal2 = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor); + unequal2->tv_sec = 0; + unequal2->tv_usec = 0; + + parcObjectTesting_AssertEqualsFunction(parcObject_Equals, x, y, z, unequal1, unequal2, NULL); + + parcObject_Release((PARCObject *) &x); + parcObject_Release((PARCObject *) &y); + parcObject_Release((PARCObject *) &z); + parcObject_Release((PARCObject *) &unequal1); + parcObject_Release((PARCObject *) &unequal2); +} + +LONGBOW_TEST_CASE(Global, parcObject_Equals_NoOverride) +{ + const PARCObjectDescriptor *descriptor = + parcObjectDescriptor_Create("override", sizeof(struct timeval), sizeof(void*), true, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &PARCObject_Descriptor, NULL); + + struct timeval *x = parcObject_CreateAndClearInstanceImpl(descriptor); + memset(x, 0, sizeof(struct timeval)); + x->tv_sec = 1; + x->tv_usec = 2; + + struct timeval *y = parcObject_CreateAndClearInstanceImpl(descriptor); + memset(y, 0, sizeof(struct timeval)); + y->tv_sec = 1; + y->tv_usec = 2; + + assertTrue(parcObject_Equals(x, y), "Expected equality"); + + struct timeval *z = parcObject_CreateAndClearInstanceImpl(descriptor); + z->tv_sec = 1; + z->tv_usec = 2; + + struct timeval *unequal1 = parcObject_CreateAndClearInstanceImpl(descriptor); + unequal1->tv_sec = 1; + unequal1->tv_usec = 1; + + struct timeval *unequal2 = parcObject_CreateAndClearInstanceImpl(descriptor); + unequal2->tv_sec = 0; + unequal2->tv_usec = 0; + + parcObjectTesting_AssertEqualsFunction(parcObject_Equals, x, y, z, unequal1, unequal2, NULL); + + parcObject_Release((PARCObject *) &x); + parcObject_Release((PARCObject *) &y); + parcObject_Release((PARCObject *) &z); + parcObject_Release((PARCObject *) &unequal1); + parcObject_Release((PARCObject *) &unequal2); + parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &descriptor); +} + +LONGBOW_TEST_CASE(Global, parcObject_Equals) +{ + _DummyObject *x = parcObject_CreateInstance(_DummyObject); + x->calledCount = 100; + _DummyObject *y = parcObject_CreateInstance(_DummyObject); + y->calledCount = 100; + _DummyObject *z = parcObject_CreateInstance(_DummyObject); + z->calledCount = 100; + + _DummyObject *unequal1 = parcObject_CreateInstance(_DummyObject); + unequal1->calledCount = 50; + + PARCObject *unequal2 = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor); + + PARCObjectDescriptor dummyMeta2 = parcObject_DescriptorName(_DummyObject); + _DummyObject *unequal3 = parcObject_CreateAndClearInstanceImpl(&dummyMeta2); + unequal3->calledCount = 100; + + PARCObject *unequal4 = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor); + + parcObjectTesting_AssertEqualsFunction(parcObject_Equals, x, y, z, unequal1, unequal2, unequal3, unequal4, NULL); + + parcObject_Release((PARCObject **) &x); + parcObject_Release((PARCObject **) &y); + parcObject_Release((PARCObject **) &z); + parcObject_Release((PARCObject **) &unequal1); + parcObject_Release((PARCObject **) &unequal2); + parcObject_Release((PARCObject **) &unequal3); + parcObject_Release((PARCObject **) &unequal4); +} + +LONGBOW_TEST_CASE(Global, parcObject_HashCode_Default) +{ + struct timeval *time = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor); + parcObject_AssertValid(time); + + time->tv_sec = 1; + time->tv_usec = 2; + + PARCHashCode hashCode = parcObject_HashCode(time); + PARCHashCode expected = parcHashCode_Hash((void *) time, sizeof(struct timeval)); + assertTrue(hashCode == expected, "Hash codes do not match. Got %" PRIPARCHashCode ", expected %" PRIPARCHashCode ".", hashCode, expected); + + parcObject_Release((PARCObject *) &time); +} + +LONGBOW_TEST_CASE(Global, parcObject_HashCode_NoOverride) +{ + const PARCObjectDescriptor *descriptor = + parcObjectDescriptor_Create("override", sizeof(struct timeval), sizeof(void*), true, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &PARCObject_Descriptor, NULL); + struct timeval *time = parcObject_CreateAndClearInstanceImpl(descriptor); + parcObject_AssertValid(time); + + time->tv_sec = 1; + time->tv_usec = 2; + + PARCHashCode hashCode = parcObject_HashCode(time); + PARCHashCode expected = parcHashCode_Hash((void *) time, sizeof(struct timeval)); + assertTrue(hashCode == expected, "Hash codes do not match. Got %" PRIPARCHashCode ", expected %" PRIPARCHashCode ".", hashCode, expected); + + parcObject_Release((PARCObject *) &time); + parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &descriptor); +} + +LONGBOW_TEST_CASE(Global, parcObject_HashCode) +{ + _DummyObject *dummy = parcObject_CreateInstance(_DummyObject); + + PARCHashCode hashCode = parcObject_HashCode(dummy); + assertTrue(hashCode == 1337, "Expected hashcode to be 1337, got %" PRIPARCHashCode, hashCode); + + parcObject_Release((PARCObject **) &dummy); +} + +LONGBOW_TEST_CASE(Global, parcObject_ToString) +{ + _DummyObject *dummy = parcObject_CreateInstance(_DummyObject); + + char *strRep = parcObject_ToString(dummy); + assertTrue(strcmp(strRep, "dummy") == 0, "Expected 'dummy' string representation, got %s", strRep); + + parcMemory_Deallocate((void **) &strRep); + parcObject_Release((PARCObject **) &dummy); +} + +LONGBOW_TEST_CASE(Global, parcObject_ToString_Default) +{ + _DummyObject *dummy = parcObject_CreateAndClearInstanceImpl(&_DummyObject_Descriptor); + + char *strRep = parcObject_ToString(dummy); + + parcMemory_Deallocate((void **) &strRep); + parcObject_Release((PARCObject **) &dummy); +} + +LONGBOW_TEST_CASE(Global, parcObject_ToString_NoOverride) +{ + const PARCObjectDescriptor *descriptor = + parcObjectDescriptor_Create("override", sizeof(struct timeval), sizeof(void*), true, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &PARCObject_Descriptor, NULL); + _DummyObject *dummy = parcObject_CreateAndClearInstanceImpl(descriptor); + + char *strRep = parcObject_ToString(dummy); + + parcMemory_Deallocate((void **) &strRep); + parcObject_Release((PARCObject **) &dummy); + parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &descriptor); +} + +LONGBOW_TEST_CASE(Global, parcObject_ToJSON_Default) +{ + size_t expectedSize = sizeof(struct timeval); + PARCObject *memory = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor); + + PARCJSON *json = parcObject_ToJSON(memory); + + const PARCJSONPair *lengthPair = parcJSON_GetPairByName(json, "objectLength"); + PARCJSONValue *lengthValue = parcJSONPair_GetValue(lengthPair); + uint64_t actualLength = parcJSONValue_GetInteger(lengthValue); + + const PARCJSONPair *alignmentPair = parcJSON_GetPairByName(json, "objectAlignment"); + PARCJSONValue *alignmentValue = parcJSONPair_GetValue(alignmentPair); + int alignment = (int) parcJSONValue_GetInteger(alignmentValue); + + assertTrue(actualLength >= expectedSize, + "Expected length to be >= %zd, actual %" PRIu64 "", expectedSize, actualLength); + assertTrue(alignment == sizeof(void *), "Expected objectAlignment to be %zd, got %d", + sizeof(void *), alignment); + + parcJSON_Release(&json); + parcObject_Release(&memory); +} + +LONGBOW_TEST_CASE(Global, parcObject_ToJSON) +{ + _DummyObject *dummy = parcObject_CreateInstance(_DummyObject); + + PARCJSON *json = parcObject_ToJSON(dummy); + char *strRep = parcJSON_ToString(json); + assertTrue(strcmp(strRep, "{ \"type\" : \"dummy\" }") == 0, "Expected fixed JSON object with a specific string representation, got %s", strRep); + + parcMemory_Deallocate((void **) &strRep); + parcJSON_Release(&json); + parcObject_Release((PARCObject **) &dummy); +} + +LONGBOW_TEST_CASE(Global, parcObject_ToJSON_NoOverride) +{ + const PARCObjectDescriptor *descriptor = + parcObjectDescriptor_Create("override", sizeof(struct timeval), sizeof(void*), true, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &PARCObject_Descriptor, NULL); + + size_t expectedSize = sizeof(struct timeval); + PARCObject *memory = parcObject_CreateAndClearInstanceImpl(descriptor); + + PARCJSON *json = parcObject_ToJSON(memory); + const PARCJSONPair *lengthPair = parcJSON_GetPairByName(json, "objectLength"); + PARCJSONValue *lengthValue = parcJSONPair_GetValue(lengthPair); + uint64_t actualLength = parcJSONValue_GetInteger(lengthValue); + + const PARCJSONPair *alignmentPair = parcJSON_GetPairByName(json, "objectAlignment"); + PARCJSONValue *alignmentValue = parcJSONPair_GetValue(alignmentPair); + int alignment = (int) parcJSONValue_GetInteger(alignmentValue); + + assertTrue(actualLength >= expectedSize, + "Expected length to be >= %zd, actual %" PRIu64 "", expectedSize, actualLength); + assertTrue(alignment == sizeof(void *), "Expected objectAlignment to be %zd, got %d", + sizeof(void *), alignment); + + parcJSON_Release(&json); + parcObject_Release(&memory); + parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &descriptor); +} + +LONGBOW_TEST_CASE(Global, parcObject_GetReferenceCount) +{ + _DummyObject *dummy = parcObject_CreateInstance(_DummyObject); + PARCReferenceCount refCount = parcObject_GetReferenceCount(dummy); + assertTrue(refCount == 1, "Expected reference count to be 1, got %" PRIu64 "", refCount); + parcObject_Release((PARCObject **) &dummy); +} + +LONGBOW_TEST_CASE(Global, parcObject_Display_Default) +{ + _DummyObject *dummy = parcObject_CreateAndClearInstanceImpl(&_DummyObject_Descriptor); + parcObject_Display(dummy, 0); + parcObject_Release((PARCObject **) &dummy); +} + +LONGBOW_TEST_CASE(Global, parcObject_Display_NoOverride) +{ + const PARCObjectDescriptor *descriptor = + parcObjectDescriptor_Create("override", sizeof(struct timeval), sizeof(void*), true, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &PARCObject_Descriptor, NULL); + + _DummyObject *dummy = parcObject_CreateAndClearInstanceImpl(descriptor); + parcObject_Display(dummy, 0); + parcObject_Release((PARCObject **) &dummy); + parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &descriptor); +} + +LONGBOW_TEST_CASE(Global, parcObject_Display) +{ + _DummyObject *dummy = parcObject_CreateInstance(_DummyObject); + parcObject_Display(dummy, 0); + parcObject_Release((PARCObject **) &dummy); +} + +LONGBOW_TEST_CASE(Global, parcObject_GetDescriptor) +{ + _DummyObject *dummy = parcObject_CreateInstance(_DummyObject); + const PARCObjectDescriptor *descriptor = parcObject_GetDescriptor(dummy); + + assertTrue(descriptor == &_DummyObject_Descriptor, "Expected pointer to _DummyObject_Descriptor"); + + parcObject_Release((PARCObject **) &dummy); +} + +LONGBOW_TEST_FIXTURE(Subclasses) +{ + LONGBOW_RUN_TEST_CASE(Subclasses, parcObject_Copy); +} + +LONGBOW_TEST_FIXTURE_SETUP(Subclasses) +{ + _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Subclasses) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + parcMemory_SetInterface(_originalMemoryProvider); + + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Subclasses, parcObject_Copy) +{ + const PARCObjectDescriptor *objectType = + parcObjectDescriptor_Create("Dummy", sizeof(_DummyObject), sizeof(void*), true, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &PARCObject_Descriptor, NULL); + + _DummyObject *dummy = parcObject_CreateInstance(_DummyObject); + parcObject_SetDescriptor(dummy, objectType); + + dummy->calledCount = 100; + + _DummyObject *dummy2 = parcObject_Copy(dummy); + + assertTrue(dummy2->calledCount == dummy->calledCount, + "Expected called counts to be the same. Got %d, expected %d.", dummy->calledCount, dummy2->calledCount); + + parcObject_Release((PARCObject **) &dummy); + parcObject_Release((PARCObject **) &dummy2); + parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &objectType); +} + +LONGBOW_TEST_FIXTURE(Locking) +{ + LONGBOW_RUN_TEST_CASE(Locking, parcObject_TryLock_Unlock); + LONGBOW_RUN_TEST_CASE(Locking, parcObject_Lock_Unlock); + LONGBOW_RUN_TEST_CASE(Locking, parcObject_TryLock_AlreadyLockedSameThread); + LONGBOW_RUN_TEST_CASE(Locking, parcObject_Lock_AlreadyLocked); +} +static uint32_t initialAllocations; + +LONGBOW_TEST_FIXTURE_SETUP(Locking) +{ + _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + initialAllocations = parcMemory_Outstanding(); + + _DummyObject *dummy = parcObject_CreateInstance(_DummyObject); + + longBowTestCase_SetClipBoardData(testCase, dummy); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Locking) +{ + _DummyObject *dummy = longBowTestCase_GetClipBoardData(testCase); + + parcObject_Release((PARCObject **) &dummy); + + if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) { + parcSafeMemory_ReportAllocation(STDOUT_FILENO); + parcMemory_SetInterface(_originalMemoryProvider); + return LONGBOW_STATUS_MEMORYLEAK; + } + parcMemory_SetInterface(_originalMemoryProvider); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Locking, parcObject_TryLock_Unlock) +{ + _DummyObject *dummy = longBowTestCase_GetClipBoardData(testCase); + + bool actual = parcObject_TryLock(dummy); + + assertTrue(actual, "Expected parcObject_TryLock to succeed."); + + actual = parcObject_IsLocked(dummy); + assertTrue(actual, "Expected parcObject_IsLocked to be true."); + + actual = parcObject_Unlock(dummy); + assertTrue(actual, "Expected parcObject_Unlock to succeed."); + + actual = parcObject_IsLocked(dummy); + assertFalse(actual, "Expected parcObject_IsLocked to be false."); +} + +LONGBOW_TEST_CASE(Locking, parcObject_Lock_Unlock) +{ + _DummyObject *dummy = longBowTestCase_GetClipBoardData(testCase); + + bool actual = parcObject_Lock(dummy); + + assertTrue(actual, "Expected parcObject_Lock to succeed."); + + actual = parcObject_IsLocked(dummy); + assertTrue(actual, "Expected parcObject_IsLocked to be true."); + + actual = parcObject_Unlock(dummy); + assertTrue(actual, "Expected parcObject_Unlock to succeed."); + + actual = parcObject_IsLocked(dummy); + assertFalse(actual, "Expected parcObject_IsLocked to be false."); +} + +LONGBOW_TEST_CASE_EXPECTS(Locking, parcObject_TryLock_AlreadyLockedSameThread, .event = &LongBowTrapCannotObtainLockEvent) +{ + _DummyObject *dummy = longBowTestCase_GetClipBoardData(testCase); + + bool actual = parcObject_TryLock(dummy); + + assertTrue(actual, "Expected parcObject_TryLock to succeed."); + + actual = parcObject_TryLock(dummy); + + assertFalse(actual, "Expected parcObject_TryLock to fail when already locked by the same thread."); + + actual = parcObject_Unlock(dummy); + assertTrue(actual, "Expected parcObject_Unlock to succeed."); +} + +LONGBOW_TEST_CASE_EXPECTS(Locking, parcObject_Lock_AlreadyLocked, .event = &LongBowTrapCannotObtainLockEvent) +{ + _DummyObject *dummy = longBowTestCase_GetClipBoardData(testCase); + + bool actual = parcObject_Lock(dummy); + + assertTrue(actual, "Expected parcObject_Lock to succeed."); + + actual = parcObject_IsLocked(dummy); + assertTrue(actual, "Expected locked object to indicate being locked."); + + parcObject_Lock(dummy); +} + +LONGBOW_TEST_FIXTURE(WaitNotify) +{ + LONGBOW_RUN_TEST_CASE(WaitNotify, parcObject_WaitNotify); + LONGBOW_RUN_TEST_CASE(WaitNotify, parcObject_WaitNotify2); + LONGBOW_RUN_TEST_CASE(WaitNotify, parcObject_WaitUntil); + LONGBOW_RUN_TEST_CASE(WaitNotify, parcObject_WaitFor); + LONGBOW_RUN_TEST_CASE(WaitNotify, parcObject_WaitNotifyAll); +} + +LONGBOW_TEST_FIXTURE_SETUP(WaitNotify) +{ + _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(WaitNotify) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + + parcMemory_SetInterface(_originalMemoryProvider); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +// Just wait until told to wakeup, then increment a counter and unlock. +static void * +waiter(void *data) +{ + _DummyObject *dummy = data; + + while (parcObject_TryLock(dummy) == false) { + ; + } + assertTrue(parcObject_IsLocked(dummy), "%p object %p not locked.", (void *) pthread_self(), (void *) dummy); + parcObject_Wait(dummy); + + dummy->val++; + parcObject_Unlock(dummy); + + return data; +} + +LONGBOW_TEST_CASE(WaitNotify, parcObject_WaitNotify) +{ + _DummyObject *dummy = parcObject_CreateInstance(_DummyObject); + + dummy->val = 0; + + pthread_t thread_A; + pthread_t thread_B; + pthread_t thread_C; + pthread_create(&thread_A, NULL, waiter, dummy); + pthread_create(&thread_B, NULL, waiter, dummy); + pthread_create(&thread_C, NULL, waiter, dummy); + + while (dummy->val != 3) { + while (parcObject_TryLock(dummy) == false) { + ; + } + parcObject_Notify(dummy); + parcObject_Unlock(dummy); + } + + pthread_join(thread_A, NULL); +// pthread_join(thread_B, NULL); +// pthread_join(thread_C, NULL); + + parcObject_Release((PARCObject **) &dummy); +} + +LONGBOW_TEST_CASE(WaitNotify, parcObject_WaitNotifyAll) +{ + _DummyObject *dummy = parcObject_CreateInstance(_DummyObject); + + dummy->val = 0; + + pthread_t thread_A; + pthread_t thread_B; + pthread_t thread_C; + pthread_create(&thread_A, NULL, waiter, dummy); + pthread_create(&thread_B, NULL, waiter, dummy); + pthread_create(&thread_C, NULL, waiter, dummy); + + while (dummy->val != 3) { + while (parcObject_TryLock(dummy) == false) { + ; + } + parcObject_NotifyAll(dummy); + parcObject_Unlock(dummy); + } + + pthread_join(thread_A, NULL); +// pthread_join(thread_B, NULL); +// pthread_join(thread_C, NULL); + + assertTrue(dummy->val == 3, "Expected the counter to be 3, actual %d", dummy->val); + + parcObject_Release((PARCObject **) &dummy); +} + +static void * +decrement(void *data) +{ + _DummyObject *dummy = data; + + while (parcObject_TryLock(dummy) == false) { + ; + } + while (dummy->val < 12) { + parcObject_Wait(dummy); + dummy->val--; + } + parcObject_Unlock(dummy); + + return data; +} + +LONGBOW_TEST_CASE(WaitNotify, parcObject_WaitNotify2) +{ + _DummyObject *dummy = parcObject_CreateInstance(_DummyObject); + + dummy->val = 0; + + pthread_t thread_A; + pthread_create(&thread_A, NULL, decrement, dummy); + + dummy->val = 2; + while (parcObject_TryLock(dummy) == false) { + ; + } + while (dummy->val <= 12) { + parcObject_Notify(dummy); + dummy->val += 2; + } + parcObject_Unlock(dummy); + + pthread_join(thread_A, NULL); + + parcObject_Release((PARCObject **) &dummy); +} + +LONGBOW_TEST_CASE(WaitNotify, parcObject_WaitUntil) +{ + _DummyObject *dummy = parcObject_CreateInstance(_DummyObject); + + dummy->val = 0; + + time_t now; + time_t then; + time(&then); + if (parcObject_Lock(dummy)) { + struct timespec future; + future.tv_sec = then + 3; + future.tv_nsec = 0; + parcObject_WaitUntil(dummy, &future); + + time(&now); + long expected = now - 1; // Subtract 1 because the future may have been computed at the 999,999,999 nanosecond mark. + assertTrue(now >= expected, "Expected now %ld, to be later than than %ld", now, expected); + parcObject_Unlock(dummy); + } + + parcObject_Release((PARCObject **) &dummy); +} + +LONGBOW_TEST_CASE(WaitNotify, parcObject_WaitFor) +{ + _DummyObject *dummy = parcObject_CreateInstance(_DummyObject); + + dummy->val = 0; + + time_t now; + time_t then; + time(&then); + if (parcObject_Lock(dummy)) { + uint64_t nanoSeconds = 1000000000; + parcObject_WaitFor(dummy, nanoSeconds); + + time(&now); + now++; // Advance now by 1 because of the precision mismatch between gettimeofday and nanosecond resolution of parcObject_WaitFor + assertTrue(now >= then + (nanoSeconds / 1000000000), + "Expected now %ld, to be later than time %" PRIu64, now, then + (nanoSeconds / 1000000000)); + parcObject_Unlock(dummy); + } + + parcObject_Release((PARCObject **) &dummy); +} + +LONGBOW_TEST_FIXTURE(Fail) +{ +} + +typedef struct { + PARCObject *value; +} TestData; + +LONGBOW_TEST_FIXTURE_SETUP(Fail) +{ + _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + data->value = parcObject_CreateInstance(_DummyObjectNoHash); + if (data->value == NULL) { + return LONGBOW_STATUS_SETUP_FAILED; + } + longBowTestCase_SetClipBoardData(testCase, data); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Fail) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + parcObject_Release(&data->value); + parcMemory_Deallocate((void **) &data); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + + parcMemory_SetInterface(_originalMemoryProvider); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false) +{ + LONGBOW_RUN_TEST_CASE(Performance, _parcObject_PrefixLength_10000000); + LONGBOW_RUN_TEST_CASE(Performance, parcObject_CreateRelease); + LONGBOW_RUN_TEST_CASE(Performance, parcObject_Create); + LONGBOW_RUN_TEST_CASE(Performance, parcObject_AcquireRelease); +} + +LONGBOW_TEST_FIXTURE_SETUP(Performance) +{ + parcMemory_SetInterface(&PARCStdlibMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Performance) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Performance, _parcObject_PrefixLength_10000000) +{ + // Test that the result is a multiple of the alignment value and greater than the size of _PARCObjectHeader. + + // Compute the power of 2 value of sizeof(void *) + unsigned int v = sizeof(void *); + unsigned int r = 0; // r will be lg(v) + + while (v >>= 1) { + r++; + } + + PARCObjectDescriptor descriptor; + + for (int i = r; i < 20; i++) { + descriptor.objectAlignment = 1 << i; + size_t actual = _parcObject_PrefixLength(&descriptor); + assertTrue((actual & (descriptor.objectAlignment - 1)) == 0, + "Alignment needs to be a multiple of %u", descriptor.objectAlignment); + } +} + +#define OBJECT_COUNT 10000000 +#define OBJECT_SIZE 1200 + +typedef struct { char bytes[OBJECT_SIZE]; } PerformanceObject; + +parcObject_Override(PerformanceObject, PARCObject); + +LONGBOW_TEST_CASE(Performance, parcObject_CreateRelease) +{ + for (int i = 0; i < OBJECT_COUNT; i++) { + PARCObject *object = parcObject_CreateInstanceImpl(&PerformanceObject_Descriptor); + + PARCObject *object1 = parcObject_Acquire(object); + PARCObject *object2 = parcObject_Acquire(object); + parcObject_Release(&object1); + parcObject_Release(&object2); + + parcObject_Release(&object); + } +} + +void *objects[OBJECT_COUNT]; + +LONGBOW_TEST_CASE(Performance, parcObject_AcquireRelease) +{ + PARCObject *object = parcObject_CreateInstanceImpl(&PerformanceObject_Descriptor); + + for (int i = 0; i < OBJECT_COUNT; i++) { + objects[i] = parcObject_Acquire(object); + } + + for (int i = 0; i < OBJECT_COUNT; i++) { + parcObject_Release(&objects[i]); + } + + parcObject_Release(&object); +} + +LONGBOW_TEST_CASE(Performance, parcObject_Create) +{ + for (int i = 0; i < OBJECT_COUNT; i++) { + objects[i] = parcObject_CreateInstanceImpl(&PerformanceObject_Descriptor); + } + + for (int i = 0; i < OBJECT_COUNT; i++) { + parcObject_Release(&objects[i]); + } +} + +LONGBOW_TEST_FIXTURE(Meta) +{ + LONGBOW_RUN_TEST_CASE(Meta, _metaDestructor_True); + LONGBOW_RUN_TEST_CASE(Meta, _metaDestructor_False); + LONGBOW_RUN_TEST_CASE(Meta, _metaDestructor_None); + + LONGBOW_RUN_TEST_CASE(Meta, parcObjectDescriptor_Create); +} + +LONGBOW_TEST_FIXTURE_SETUP(Meta) +{ + _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + _DummyObject *data; + parcMemory_MemAlign((void **) &data, sizeof(void *), sizeof(_DummyObject)); + data->val = 10; + longBowTestCase_SetClipBoardData(testCase, data); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Meta) +{ + _DummyObject *data = longBowTestCase_GetClipBoardData(testCase); + parcMemory_Deallocate((void **) &data); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + parcMemory_SetInterface(_originalMemoryProvider); + if (outstandingAllocations != 0) { + printf("%s leaks %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Meta, parcObjectDescriptor_Create) +{ + const PARCObjectDescriptor *interface = parcObjectDescriptor_Create("Meta", + sizeof(struct timeval), sizeof(void*), + true, + _meta_destructor_true, NULL, _meta_copy, _meta_toString, + _meta_equals, _meta_compare, _meta_hashCode, _meta_toJson, NULL, + &PARCObject_Descriptor, NULL); + + assertNotNull(interface, "Expected interface instance to be allocated correctly."); + + parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &interface); + assertNull(interface, "Expected parcObjectDescriptor_Destroy to NULL the input pointer"); +} + +LONGBOW_TEST_CASE(Meta, _metaDestructor_True) +{ + const PARCObjectDescriptor *interface = + parcObjectDescriptor_Create("Meta", sizeof(struct timeval), sizeof(void*), true, + _meta_destructor_true, NULL, _meta_copy, _meta_toString, _meta_equals, _meta_compare, _meta_hashCode, _meta_toJson, NULL, + &PARCObject_Descriptor, NULL); + _DummyObject *data = longBowTestCase_GetClipBoardData(testCase); + bool actual = _parcObject_Destructor(interface, (PARCObject **) &data); + + assertTrue(actual, "Expected destructor to return true."); + + parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &interface); +} + +LONGBOW_TEST_CASE(Meta, _metaDestructor_False) +{ + const PARCObjectDescriptor *descriptor = + parcObjectDescriptor_Create("Meta", sizeof(struct timeval), sizeof(void*), true, + _meta_destructor_false, NULL, _meta_copy, _meta_toString, _meta_equals, _meta_compare, _meta_hashCode, _meta_toJson, NULL, + &PARCObject_Descriptor, NULL); + _DummyObject *data = longBowTestCase_GetClipBoardData(testCase); + bool actual = _parcObject_Destructor(descriptor, (PARCObject **) &data); + + assertNull(data, "Expected destructor function to have been called to nullify the reference."); + assertFalse(actual, "Expected destructor to return false."); + + parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &descriptor); +} + +LONGBOW_TEST_CASE(Meta, _metaDestructor_None) +{ + const PARCObjectDescriptor *interface = parcObjectDescriptor_Create("Meta", sizeof(struct timeval), sizeof(void*), true, + NULL, NULL, _meta_copy, _meta_toString, _meta_equals, _meta_compare, _meta_hashCode, _meta_toJson, NULL, &PARCObject_Descriptor, NULL); + _DummyObject *data = longBowTestCase_GetClipBoardData(testCase); + _parcObject_Destructor(interface, (void **) &data); + + assertNotNull(data, "Expected destructor function to have been called to nullify the reference."); + + parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &interface); +} + +LONGBOW_TEST_FIXTURE(PARCObjectDescriptor) +{ + LONGBOW_RUN_TEST_CASE(PARCObjectDescriptor, parcObjectDescriptor_Create); + LONGBOW_RUN_TEST_CASE(PARCObjectDescriptor, parcObjectDescriptor_CreateExtension); + LONGBOW_RUN_TEST_CASE(PARCObjectDescriptor, parcObjectDescriptor_GetSuperType); + LONGBOW_RUN_TEST_CASE(PARCObjectDescriptor, parcObjectDescriptor_GetTypeState); +} + +LONGBOW_TEST_FIXTURE_SETUP(PARCObjectDescriptor) +{ + longBowTestCase_SetInt(testCase, "initialAllocations", parcMemory_Outstanding()); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(PARCObjectDescriptor) +{ + int initialAllocations = longBowTestCase_GetInt(testCase, "initialAllocations"); + + uint32_t outstandingAllocations = parcMemory_Outstanding() - initialAllocations; + + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations); + parcSafeMemory_ReportAllocation(STDOUT_FILENO); + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(PARCObjectDescriptor, parcObjectDescriptor_Create) +{ + const PARCObjectDescriptor *descriptor = parcObjectDescriptor_Create("Meta", sizeof(struct timeval), sizeof(void*), true, + NULL, NULL, _meta_copy, _meta_toString, _meta_equals, _meta_compare, _meta_hashCode, _meta_toJson, NULL, &PARCObject_Descriptor, NULL); + + parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &descriptor); +} + +LONGBOW_TEST_CASE(PARCObjectDescriptor, parcObjectDescriptor_CreateExtension) +{ + PARCObjectDescriptor *descriptor = parcObjectDescriptor_Create("Meta", sizeof(struct timeval), sizeof(void*), true, + NULL, NULL, _meta_copy, _meta_toString, _meta_equals, _meta_compare, _meta_hashCode, _meta_toJson, NULL, &PARCObject_Descriptor, NULL); + + PARCObjectDescriptor *extension = parcObjectDescriptor_CreateExtension(descriptor, "Extension"); + + parcObjectDescriptor_Destroy(&extension); + parcObjectDescriptor_Destroy(&descriptor); +} + +LONGBOW_TEST_CASE(PARCObjectDescriptor, parcObjectDescriptor_GetSuperType) +{ + PARCObjectDescriptor *descriptor = parcObjectDescriptor_Create("Meta", sizeof(struct timeval), sizeof(void*), true, + NULL, NULL, _meta_copy, _meta_toString, _meta_equals, _meta_compare, _meta_hashCode, _meta_toJson, NULL, &PARCObject_Descriptor, NULL); + + const PARCObjectDescriptor *superType = parcObjectDescriptor_GetSuperType(descriptor); + + assertTrue(superType == &PARCObject_Descriptor, "Expected a pointer to PARCObject_Descriptor"); + + parcObjectDescriptor_Destroy(&descriptor); +} + +LONGBOW_TEST_CASE(PARCObjectDescriptor, parcObjectDescriptor_GetTypeState) +{ + PARCObjectDescriptor *descriptor = parcObjectDescriptor_Create("Meta", sizeof(struct timeval), sizeof(void*), true, + NULL, NULL, _meta_copy, _meta_toString, _meta_equals, + _meta_compare, _meta_hashCode, _meta_toJson, NULL, + &PARCObject_Descriptor, + (PARCObjectTypeState *) &PARCObject_Descriptor); + + PARCObjectTypeState *state = parcObjectDescriptor_GetTypeState(descriptor); + + assertTrue(state == &PARCObject_Descriptor, "Expected a pointer to PARCObject_Descriptor"); + + parcObjectDescriptor_Destroy(&descriptor); +} + +LONGBOW_TEST_FIXTURE(StaticObjects) +{ + LONGBOW_RUN_TEST_CASE(StaticObjects, parcObject_WrapImpl); + LONGBOW_RUN_TEST_CASE(StaticObjects, parcObject_InitInstanceImpl); + LONGBOW_RUN_TEST_CASE(StaticObjects, parcObject_InitAndClearInstanceImpl); +} + +LONGBOW_TEST_FIXTURE_SETUP(StaticObjects) +{ + _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(StaticObjects) +{ + parcMemory_SetInterface(_originalMemoryProvider); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(StaticObjects, parcObject_WrapImpl) +{ + char *origin = (char[parcObject_TotalSize(sizeof(void*), 10)]) { 0 }; + + PARCObject *result = parcObject_WrapImpl(origin, &parcObject_DescriptorName(PARCObject)); + + parcObject_AssertValid(result); + + parcObject_Release(&result); +} + +PARCObject *globalObject = parcObject_Instance(PARCObject, sizeof(void*), 10); + +LONGBOW_TEST_CASE(StaticObjects, parcObject_InitInstanceImpl) +{ + parcObject_InitInstanceImpl(globalObject, &PARCObject_Descriptor); + + parcObject_AssertValid(globalObject); + +// parcObject_Release(&globalObject); +} + +LONGBOW_TEST_CASE(StaticObjects, parcObject_InitAndClearInstanceImpl) +{ + parcObject_InitAndClearInstanceImpl(globalObject, &PARCObject_Descriptor); + + parcObject_AssertValid(globalObject); + +// parcObject_Release(&globalObject); +} + +LONGBOW_TEST_FIXTURE(Synchronization) +{ + LONGBOW_RUN_TEST_CASE(Synchronization, parcObject_SynchronizeBegin); +} + +LONGBOW_TEST_FIXTURE_SETUP(Synchronization) +{ + _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Synchronization) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO); + + parcMemory_SetInterface(_originalMemoryProvider); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Synchronization, parcObject_SynchronizeBegin) +{ + PARCObject *dummy = parcObject_CreateInstance(_DummyObject); + + bool result = parcObject_BarrierSet(dummy); + assertTrue(result, "Expected parcObject_BarrierSet to always return true."); + + _PARCObjectHeader *header = _parcObject_Header(dummy); + assertTrue(header->barrier, "Expected the header barrier to be set."); + + result = parcObject_BarrierUnset(dummy); + assertFalse(result, "Expected parcObject_BarrierUnset to always return false."); + assertFalse(header->barrier, "Expected the header barrier to NOT be set."); + + parcObject_Release(&dummy); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parcObject); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} + diff --git a/libparc/parc/algol/test/test_parc_PathName.c b/libparc/parc/algol/test/test_parc_PathName.c new file mode 100755 index 00000000..b596aaa2 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_PathName.c @@ -0,0 +1,458 @@ +/* + * 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 "../parc_PathName.c" +#include <LongBow/unit-test.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../parc_SafeMemory.h" +#include <parc/testing/parc_ObjectTesting.h> + +#define PATH_SEGMENT "A" + +LONGBOW_TEST_RUNNER(parc_PathName) +{ + // 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(Local); + LONGBOW_RUN_TEST_FIXTURE(AcquireRelease); + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_PathName) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_PathName) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(AcquireRelease) +{ + LONGBOW_RUN_TEST_CASE(AcquireRelease, parcPathName_Create); + LONGBOW_RUN_TEST_CASE(AcquireRelease, parcPathName_Release); + LONGBOW_RUN_TEST_CASE(AcquireRelease, parcPathName_AcquireRelease); +} + +LONGBOW_TEST_FIXTURE_SETUP(AcquireRelease) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(AcquireRelease) +{ + 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(AcquireRelease, parcPathName_Create) +{ + PARCPathName *pathName = parcPathName_Create(); + assertNotNull(pathName, "Expected a non-null pointer"); + + parcPathName_Release(&pathName); + assertNull(pathName, "Expected parcPathName_Release to null the pointer"); +} + +LONGBOW_TEST_CASE(AcquireRelease, parcPathName_Release) +{ + PARCPathName *pathName = parcPathName_Create(); + assertNotNull(pathName, "Expected a non-null pointer"); + + parcPathName_Release(&pathName); + assertNull(pathName, "Expected parcPathName_Release to null the pointer"); +} + +LONGBOW_TEST_CASE(AcquireRelease, parcPathName_AcquireRelease) +{ + PARCPathName *original = parcPathName_Create(); + assertNotNull(original, "Expected non-null result from parcPathName_Create()"); + + PARCPathName *reference = parcPathName_Acquire(original); + assertTrue(original == reference, "Expected the reference to be equal to the original."); + + parcPathName_Release(&original); + assertNull(original, "Expected parcDeque_Release to null the pointer"); + + parcPathName_Append(reference, (void *) "Hello"); + size_t expected = 1; + size_t actual = parcPathName_Size(reference); + assertTrue(expected == actual, + "Expected size %zd, actual %zd", expected, actual); + parcPathName_Release(&reference); +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcPathName_Create); + + LONGBOW_RUN_TEST_CASE(Global, parcPathName_Size); + LONGBOW_RUN_TEST_CASE(Global, parcPathName_Append); + LONGBOW_RUN_TEST_CASE(Global, parcPathName_Prepend); + LONGBOW_RUN_TEST_CASE(Global, parcPathName_IsAbsolute); + LONGBOW_RUN_TEST_CASE(Global, parcPathName_MakeAbsolute); + LONGBOW_RUN_TEST_CASE(Global, parcPathName_Parse_AbsolutePath); + LONGBOW_RUN_TEST_CASE(Global, parcPathName_Parse_AbsolutePath_Limited); + LONGBOW_RUN_TEST_CASE(Global, parcPathName_Parse_RelativePath); + LONGBOW_RUN_TEST_CASE(Global, parcPathName_ToString_AbsolutePath); + LONGBOW_RUN_TEST_CASE(Global, parcPathName_ToString_RelativePath); + LONGBOW_RUN_TEST_CASE(Global, parcPathName_Head); + LONGBOW_RUN_TEST_CASE(Global, parcPathName_Tail); + LONGBOW_RUN_TEST_CASE(Global, parcPathName_Tail_ExceedsLength); + LONGBOW_RUN_TEST_CASE(Global, parcPathName_Equals); + LONGBOW_RUN_TEST_CASE(Global, parcPathName_Copy); +} + +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, parcPathName_Size) +{ + char *path = "/a/b/c"; + PARCPathName *pathName = parcPathName_Parse(path); + assertNotNull(pathName, "Expected a non-null pointer"); + assertTrue(pathName->isAbsolute, "Expected the PARCPathName to be absolute."); + + assertTrue(parcPathName_Size(pathName) == 3, "Expected 3, actual %zu", parcPathName_Size(pathName)); + parcPathName_Release(&pathName); +} + +LONGBOW_TEST_CASE(Global, parcPathName_Prepend) +{ + PARCPathName *pathName = parcPathName_Create(); + size_t size = 1000; + + char expected[10]; + for (size_t i = 0; i < size; i++) { + sprintf(expected, "%zd", i); + parcPathName_Prepend(pathName, expected); + } + assertNotNull(pathName, "Expected a non-null pointer"); + + size_t actual = parcPathName_Size(pathName); + assertTrue(size == actual, + "Expected %zd, actual %zd", size, actual); + + for (size_t i = 0; i < size; i++) { + sprintf(expected, "%zd", size - i - 1); + char *segment = parcDeque_GetAtIndex(pathName->path, i); + assertTrue(strcmp(segment, expected) == 0, + "Expected %s, actual %s", expected, segment); + } + + parcPathName_Release(&pathName); +} + +LONGBOW_TEST_CASE(Global, parcPathName_Append) +{ + PARCPathName *pathName = parcPathName_Create(); + size_t size = 1000; + + char expected[10]; + for (size_t i = 0; i < size; i++) { + sprintf(expected, "%zd", i); + parcPathName_Append(pathName, expected); + } + assertNotNull(pathName, "Expected a non-null pointer"); + + size_t actual = parcPathName_Size(pathName); + assertTrue(size == actual, + "Expected %zd, actual %zd", size, actual); + + for (size_t i = 0; i < size; i++) { + sprintf(expected, "%zd", i); + char *segment = parcDeque_GetAtIndex(pathName->path, i); + assertTrue(strcmp(segment, expected) == 0, + "Expected %s, actual %s", expected, segment); + } + + parcPathName_Release(&pathName); +} + +LONGBOW_TEST_CASE(Global, parcPathName_Create) +{ + PARCPathName *pathName = parcPathName_Create(); + assertNotNull(pathName, "Expected a non-null pointer"); + + parcPathName_Release(&pathName); + assertNull(pathName, "Expected parcPathName_Release to null the pointer"); +} + +LONGBOW_TEST_CASE(Global, parcPathName_IsAbsolute) +{ + char *path = "/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/aa/bb/cc/dd/ee/ff/gg/hh/ii/jj/kk/ll/mm/nn/oo/pp/qq/rr/ss/tt/uu/vv/ww/xx/yy/zz"; + PARCPathName *pathName = parcPathName_Parse(path); + assertNotNull(pathName, "Expected a non-null pointer"); + assertTrue(parcPathName_IsAbsolute(pathName), "Expected the PARCPathName to be absolute."); + + parcPathName_Release(&pathName); +} + +LONGBOW_TEST_CASE(Global, parcPathName_MakeAbsolute) +{ +#define PATH "a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z" + char *expected = PATH; + PARCPathName *pathName = parcPathName_Parse(expected); + assertNotNull(pathName, "Expected a non-null pointer"); + assertFalse(pathName->isAbsolute, "Expected the PARCPathName to be relative."); + + parcPathName_MakeAbsolute(pathName, true); + + char *actual = parcPathName_ToString(pathName); + assertTrue(strcmp("/" PATH, actual) == 0, + "Expected '%s' actual '%s'", expected, actual); + parcMemory_Deallocate((void **) &actual); + parcPathName_Release(&pathName); +} + +LONGBOW_TEST_CASE(Global, parcPathName_Parse_AbsolutePath) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + for (int i = 0; i < 1000; i++) { + parcBufferComposer_Format(composer, "/%d", i); + } + + PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); + char *path = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + + PARCPathName *pathName = parcPathName_Parse(path); + assertNotNull(pathName, "Expected a non-null pointer"); + assertTrue(pathName->isAbsolute, "Expected the PARCPathName to be absolute."); + + + char *actual = parcPathName_ToString(pathName); + assertTrue(strcmp(path, actual) == 0, "Expected %s, actual %s", path, actual); + + parcMemory_Deallocate((void **) &actual); + parcMemory_Deallocate((void **) &path); + + parcPathName_Release(&pathName); + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, parcPathName_Parse_AbsolutePath_Limited) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + for (int i = 0; i < 10; i++) { + parcBufferComposer_Format(composer, "/%d", i); + } + parcBufferComposer_Format(composer, "?hello world"); + + PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); + char *path = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + + size_t limit = strchr(path, '?') - path; + PARCPathName *pathName = parcPathName_ParseToLimit(limit, path); + + assertNotNull(pathName, "Expected a non-null pointer"); + assertTrue(pathName->isAbsolute, "Expected the PARCPathName to be absolute."); + + path[limit] = 0; + char *actual = parcPathName_ToString(pathName); + assertTrue(strcmp(path, actual) == 0, "Expected %s, actual %s", path, actual); + + parcMemory_Deallocate((void **) &actual); + parcMemory_Deallocate((void **) &path); + + parcPathName_Release(&pathName); + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, parcPathName_Parse_RelativePath) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + for (int i = 0; i < 1000; i++) { + parcBufferComposer_Format(composer, "%d/", i); + } + parcBufferComposer_Format(composer, "%d", 1000); + + PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); + char *expected = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + + PARCPathName *pathName = parcPathName_Parse(expected); + assertNotNull(pathName, "Expected a non-null pointer"); + assertFalse(pathName->isAbsolute, "Expected the PARCPathName to be relative."); + + char *actual = parcPathName_ToString(pathName); + assertTrue(strcmp(expected, actual) == 0, + "Expected '%s' actual '%s'", expected, actual); + parcMemory_Deallocate((void **) &actual); + parcMemory_Deallocate((void **) &expected); + + parcPathName_Release(&pathName); + + parcBufferComposer_Release(&composer); +} + +LONGBOW_TEST_CASE(Global, parcPathName_ToString_AbsolutePath) +{ + char *path = "/a/b/c"; + PARCPathName *pathName = parcPathName_Parse(path); + assertNotNull(pathName, "Expected a non-null pointer"); + assertTrue(pathName->isAbsolute, "Expected the PARCPathName to be absolute."); + + char *actual = parcPathName_ToString(pathName); + + assertTrue(strcmp(path, actual) == 0, "Expected '%s' actual '%s'", path, actual); + + parcMemory_Deallocate((void **) &actual); + + parcPathName_Release(&pathName); +} + +LONGBOW_TEST_CASE(Global, parcPathName_ToString_RelativePath) +{ + char *path = "a/b/c"; + PARCPathName *pathName = parcPathName_Parse(path); + assertNotNull(pathName, "Expected a non-null pointer"); + assertFalse(pathName->isAbsolute, "Expected the PARCPathName to be relative."); + + char *actual = parcPathName_ToString(pathName); + + assertTrue(strcmp(path, actual) == 0, "Expected '%s' actual '%s'", path, actual); + + parcMemory_Deallocate((void **) &actual); + + parcPathName_Release(&pathName); +} + +LONGBOW_TEST_CASE(Global, parcPathName_Head) +{ + PARCPathName *original = parcPathName_Parse("/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT); + assertNotNull(original, "Expected a non-null pointer"); + + PARCPathName *expected = parcPathName_Parse("/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT); + PARCPathName *actual = parcPathName_Head(original, 3); + + assertTrue(parcPathName_Equals(expected, actual), + "expected did not match actual"); + + parcPathName_Release(&original); + parcPathName_Release(&expected); + parcPathName_Release(&actual); +} + +LONGBOW_TEST_CASE(Global, parcPathName_Tail) +{ + PARCPathName *original = parcPathName_Parse("/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT); + assertNotNull(original, "Expected a non-null pointer"); + + PARCPathName *expected = parcPathName_Parse(PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT); + PARCPathName *actual = parcPathName_Tail(original, 3); + + assertTrue(parcPathName_Equals(expected, actual), + "expected did not match actual"); + + parcPathName_Release(&original); + parcPathName_Release(&expected); + parcPathName_Release(&actual); +} + +LONGBOW_TEST_CASE(Global, parcPathName_Tail_ExceedsLength) +{ + PARCPathName *original = parcPathName_Parse("/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT); + assertNotNull(original, "Expected a non-null pointer"); + + PARCPathName *actual = parcPathName_Tail(original, 10000000); + + parcPathName_MakeAbsolute(original, false); + + assertTrue(parcPathName_Equals(original, actual), + "expected did not match actual"); + + parcPathName_Release(&original); + parcPathName_Release(&actual); +} + +LONGBOW_TEST_CASE(Global, parcPathName_Equals) +{ + PARCPathName *x = parcPathName_Parse("/a/b/c/d/"); + PARCPathName *y = parcPathName_Parse("/a/b/c/d/"); + PARCPathName *z = parcPathName_Parse("/a/b/c/d/"); + PARCPathName *u1 = parcPathName_Parse("/a/b/c/d/e"); + PARCPathName *u2 = parcPathName_Parse("/a/b/c/"); + PARCPathName *u3 = parcPathName_Parse("a/b/c/"); + + parcObjectTesting_AssertEqualsFunction(parcPathName_Equals, x, y, z, u1, u2, u3, NULL); + + parcPathName_Release(&x); + parcPathName_Release(&y); + parcPathName_Release(&z); + parcPathName_Release(&u1); + parcPathName_Release(&u2); + parcPathName_Release(&u3); +} + +LONGBOW_TEST_CASE(Global, parcPathName_Copy) +{ + PARCPathName *x = parcPathName_Parse("/a/b/c/d/"); + PARCPathName *y = parcPathName_Copy(x); + + assertTrue(parcPathName_Equals(x, y), "Expected the copy to be equal to the original."); + + parcPathName_Release(&x); + parcPathName_Release(&y); +} + +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(parc_PathName); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_PriorityQueue.c b/libparc/parc/algol/test/test_parc_PriorityQueue.c new file mode 100644 index 00000000..d42066e4 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_PriorityQueue.c @@ -0,0 +1,492 @@ +/* + * 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 <inttypes.h> + +#include "../parc_PriorityQueue.c" +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(parc_PriorityQueue) +{ + // 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(parc_PriorityQueue) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_PriorityQueue) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Add); + LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Add_Expand); + LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Clear); + LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Clear_Destroy); + LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Create); + LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_ParcFreeDestroyer); + LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Peek); + LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Poll); + LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Peek_Empty); + LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Poll_Empty); + LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Size); + LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Uint64CompareTo); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + 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(Global, parcPriorityQueue_Add) +{ + PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL); + uint64_t data[] = { 60, 70, 50, 71, 72, 55 }; + size_t count = 6; + + for (int i = 0; i < count; i++) { + parcPriorityQueue_Add(queue, &data[i]); + } + + assertTrue(parcPriorityQueue_Size(queue) == count, "Wrong size got %zu expected %zu", parcPriorityQueue_Size(queue), count); + parcPriorityQueue_Destroy(&queue); +} + +LONGBOW_TEST_CASE(Global, parcPriorityQueue_Add_Expand) +{ + PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL); + size_t capacity = queue->capacity; + for (int i = 0; i <= capacity; i++) { + parcPriorityQueue_Add(queue, &capacity); + } + + assertTrue(capacity < queue->capacity, "Did not expand queue before %zu after %zu", capacity, queue->capacity); + parcPriorityQueue_Destroy(&queue); +} + + +LONGBOW_TEST_CASE(Global, parcPriorityQueue_Clear) +{ + PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL); + uint64_t data[] = { 60, 70, 50, 71, 72, 55 }; + size_t count = 6; + + for (int i = 0; i < count; i++) { + parcPriorityQueue_Add(queue, &data[i]); + } + + parcPriorityQueue_Clear(queue); + + assertTrue(parcPriorityQueue_Size(queue) == 0, "Wrong size got %zu expected %d", parcPriorityQueue_Size(queue), 0); + parcPriorityQueue_Destroy(&queue); +} + +LONGBOW_TEST_CASE(Global, parcPriorityQueue_Clear_Destroy) +{ + PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, parcPriorityQueue_ParcFreeDestroyer); + uint64_t *value = parcMemory_Allocate(sizeof(uint64_t)); + assertNotNull(value, "parcMemory_Allocate(%zu) returned NULL", sizeof(uint64_t)); + *value = 1; + parcPriorityQueue_Add(queue, value); + + parcPriorityQueue_Clear(queue); + + assertTrue(parcPriorityQueue_Size(queue) == 0, "Wrong size got %zu expected %d", parcPriorityQueue_Size(queue), 0); + parcPriorityQueue_Destroy(&queue); + + assertTrue(parcMemory_Outstanding() == 0, "Memory imbalance after clear with destroy: %u", parcMemory_Outstanding()); +} + +LONGBOW_TEST_CASE(Global, parcPriorityQueue_Create) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Global, parcPriorityQueue_ParcFreeDestroyer) +{ + size_t before_balance = parcMemory_Outstanding(); + uint64_t *a = parcMemory_Allocate(sizeof(uint64_t)); + assertNotNull(a, "parcMemory_Allocate(%zu) returned NULL", sizeof(uint64_t)); + *a = 1; + parcPriorityQueue_ParcFreeDestroyer((void **) &a); + size_t after_balance = parcMemory_Outstanding(); + assertTrue(a == NULL, "Did not null double pointer"); + assertTrue(before_balance == after_balance, "Memory imbalance after destroy: before %zu after %zu", before_balance, after_balance); +} + +LONGBOW_TEST_CASE(Global, parcPriorityQueue_Peek) +{ + PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL); + uint64_t data[] = { 60, 70, 50, 71, 72, 55 }; + size_t count = 6; + + for (int i = 0; i < count; i++) { + parcPriorityQueue_Add(queue, &data[i]); + } + + uint64_t *test = parcPriorityQueue_Peek(queue); + + assertTrue(*test == 50, "Wrong head element, expected 50 got %" PRIu64 "", *test); + assertTrue(parcPriorityQueue_Size(queue) == count, "Queue should not have shunk, size %zu expected %zu", parcPriorityQueue_Size(queue), count); + parcPriorityQueue_Destroy(&queue); +} + +LONGBOW_TEST_CASE(Global, parcPriorityQueue_Poll) +{ + PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL); + uint64_t data[] = { 60, 70, 50, 71, 72, 55 }; + size_t count = 6; + + for (int i = 0; i < count; i++) { + parcPriorityQueue_Add(queue, &data[i]); + } + + uint64_t *test = parcPriorityQueue_Poll(queue); + + assertTrue(*test == 50, "Wrong head element, expected 50 got %" PRIu64 "", *test); + assertTrue(queue->size == count - 1, "Queue should have shunk, size %zu expected %zu", queue->size, count - 1); + parcPriorityQueue_Destroy(&queue); +} + +LONGBOW_TEST_CASE(Global, parcPriorityQueue_Peek_Empty) +{ + PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL); + uint64_t *test = parcPriorityQueue_Peek(queue); + assertNull(test, "Peek on empty queue should return null, got %p", (void *) test); + parcPriorityQueue_Destroy(&queue); +} + +LONGBOW_TEST_CASE(Global, parcPriorityQueue_Poll_Empty) +{ + PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL); + uint64_t *test = parcPriorityQueue_Poll(queue); + assertNull(test, "Poll on empty queue should return null, got %p", (void *) test); + parcPriorityQueue_Destroy(&queue); +} + +LONGBOW_TEST_CASE(Global, parcPriorityQueue_Size) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Global, parcPriorityQueue_Uint64CompareTo) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_BubbleUp_True); + LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_BubbleUp_False); + LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_Expand); + LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_LeftChildIndex); + LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_ParentIndex); + LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_RightChildIndex); + LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_Swap); + LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_TrickleDown); + LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_TrickleLeftChild_True); + LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_TrickleLeftChild_False); + LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_TrickleRightChild_Case1_True); + LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_TrickleRightChild_Case2_True); + LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_TrickleRightChild_Case1_False); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + 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, parcPriorityQueue_BubbleUp_True) +{ + PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL); + uint64_t data[] = { 50, 6 }; + + queue->array[0].data = &data[0]; + queue->array[1].data = &data[1]; + queue->size = 2; + + _bubbleUp(queue, 1); + assertTrue(queue->array[0].data == &data[1], "Element 6 did not make it to the root"); + + parcPriorityQueue_Destroy(&queue); +} + +LONGBOW_TEST_CASE(Local, parcPriorityQueue_BubbleUp_False) +{ + PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL); + uint64_t data[] = { 50, 60 }; + + queue->array[0].data = &data[0]; + queue->array[1].data = &data[1]; + queue->size = 2; + + _bubbleUp(queue, 1); + assertTrue(queue->array[0].data == &data[0], "Element 60 did not stay as child"); + + parcPriorityQueue_Destroy(&queue); +} + + +LONGBOW_TEST_CASE(Local, parcPriorityQueue_Expand) +{ + PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL); + size_t before_capacity = queue->capacity; + _expand(queue); + size_t after_capacity = queue->capacity; + + assertTrue(before_capacity < after_capacity, "Expected after capacity %zu to be larger than before %zu", after_capacity, before_capacity); + parcPriorityQueue_Destroy(&queue); +} + +LONGBOW_TEST_CASE(Local, parcPriorityQueue_LeftChildIndex) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Local, parcPriorityQueue_ParentIndex) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Local, parcPriorityQueue_RightChildIndex) +{ + testUnimplemented(""); +} + +/** + * Swaps two elements + */ +LONGBOW_TEST_CASE(Local, parcPriorityQueue_Swap) +{ + PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL); + uint64_t data[] = { 50, 6 }; + + queue->array[0].data = &data[0]; + queue->array[1].data = &data[1]; + queue->size = 2; + + _swap(queue, 0, 1); + assertTrue(queue->array[0].data == &data[1], "array[0] does not equal data[1]: %p != %p", + (void *) queue->array[0].data, (void *) &data[1]); + assertTrue(queue->array[1].data == &data[0], "array[1] does not equal data[0]: %p != %p", + (void *) queue->array[1].data, (void *) &data[0]); + + parcPriorityQueue_Destroy(&queue); +} + +/** + * Tests each case in TrickleDown: + * - right child exists, then + * - no right child, only left child, then + * - no child + * + * 60 50 + * / \ / \ + * 70 50 ====> 70 55 + * / \ / \ / \ / \ + * 71 72 55 x 71 72 60 x + */ +LONGBOW_TEST_CASE(Local, parcPriorityQueue_TrickleDown) +{ + PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL); + uint64_t data[] = { 60, 70, 50, 71, 72, 55 }; + + queue->size = 6; + for (int i = 0; i < queue->size; i++) { + queue->array[i].data = &data[i]; + } + + _trickleDown(queue, 0); + assertTrue(*((uint64_t *) queue->array[0].data) == 50, + "Root not 50, got %" PRIu64 "\n", + (uint64_t) *((uint64_t *) queue->array[0].data)); + assertTrue(*((uint64_t *) queue->array[2].data) == 55, + "Right not 55, got %" PRIu64 "\n", + (uint64_t) *((uint64_t *) queue->array[2].data)); + assertTrue(*((uint64_t *) queue->array[5].data) == 60, + "Last not 60, got %" PRIu64 "\n", + (uint64_t) *((uint64_t *) queue->array[5].data)); + + parcPriorityQueue_Destroy(&queue); +} + +/** + * Tests the TRUE case of this condition + * + * Case 3: Left child exists (right does not) and l.value < n.value + * In this case, swap(n.index, l.index) and set n.index = l.index + * 50 6 + * / \ ===> / \ + * 6 x 50 x + */ +LONGBOW_TEST_CASE(Local, parcPriorityQueue_TrickleLeftChild_True) +{ + PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL); + uint64_t data[] = { 50, 6 }; + + queue->array[0].data = &data[0]; + queue->array[1].data = &data[1]; + queue->size = 2; + + size_t nextElementIndex = _trickleLeftChild(queue, 0, 1); + assertTrue(nextElementIndex == 1, "nextElementIndex should have been left child 1, got %zu\n", nextElementIndex); + + parcPriorityQueue_Destroy(&queue); +} + +/** + * Tests the FALSE case of this condition + * + * Case 3: Left child exists (right does not) and l.value < n.value + * In this case, swap(n.index, l.index) and set n.index = l.index + * 50 6 + * / \ ===> / \ + * 6 x 50 x + */ +LONGBOW_TEST_CASE(Local, parcPriorityQueue_TrickleLeftChild_False) +{ + PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL); + uint64_t data[] = { 6, 50 }; + + queue->array[0].data = &data[0]; + queue->array[1].data = &data[1]; + queue->size = 2; + + size_t nextElementIndex = _trickleLeftChild(queue, 0, 1); + assertTrue(nextElementIndex == 0, "nextElementIndex should have been root 0, got %zu\n", nextElementIndex); + + parcPriorityQueue_Destroy(&queue); +} + + +/** + * Tests the TRUE case + * + * Case 1: Right child exists and r.value < n.value && r.value < l.value + * In this case, swap(n.index, r.index) and set n.index = r.index. + * 50 6 + * / \ ===> / \ + * 9 6 9 50 + */ +LONGBOW_TEST_CASE(Local, parcPriorityQueue_TrickleRightChild_Case1_True) +{ + PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL); + uint64_t data[] = { 50, 9, 6 }; + + queue->array[0].data = &data[0]; + queue->array[1].data = &data[1]; + queue->array[2].data = &data[2]; + queue->size = 3; + + size_t nextElementIndex = _trickleRightChild(queue, 0, 1, 2); + assertTrue(nextElementIndex == 2, "nextElementIndex should have been right 2, got %zu\n", nextElementIndex); + + parcPriorityQueue_Destroy(&queue); +} + +/** + * Tests the FALSE case + * + * Case 1: Right child exists and r.value < n.value && r.value < l.value + * In this case, swap(n.index, r.index) and set n.index = r.index. + * 50 6 + * / \ ===> / \ + * 9 6 9 50 + */ +LONGBOW_TEST_CASE(Local, parcPriorityQueue_TrickleRightChild_Case1_False) +{ + PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL); + + // r.value not < n.value + uint64_t data[] = { 6, 9, 50 }; + + queue->array[0].data = &data[0]; + queue->array[1].data = &data[1]; + queue->array[2].data = &data[2]; + queue->size = 3; + + size_t nextElementIndex = _trickleRightChild(queue, 0, 1, 2); + assertTrue(nextElementIndex == 0, "nextElementIndex should have been root 0, got %zu\n", nextElementIndex); + + parcPriorityQueue_Destroy(&queue); +} + +/** + * Tests the TRUE case + * + * Case 2: Right child exists and r.value < n.value && l.value <= r.value + * In this case swap(n.index, l.index) and set n.index = l.index + * This makes sense by transitivity that l <= r < n, so swap(n,l) satisfies the invariant. + * 50 6 + * / \ ===> / \ + * 6 9 50 9 + */ +LONGBOW_TEST_CASE(Local, parcPriorityQueue_TrickleRightChild_Case2_True) +{ + PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL); + uint64_t data[] = { 50, 6, 9 }; + + queue->array[0].data = &data[0]; + queue->array[1].data = &data[1]; + queue->array[2].data = &data[2]; + queue->size = 3; + + size_t nextElementIndex = _trickleRightChild(queue, 0, 1, 2); + assertTrue(nextElementIndex == 1, "nextElementIndex should have been left 1, got %zu\n", nextElementIndex); + + parcPriorityQueue_Destroy(&queue); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_PriorityQueue); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_Properties.c b/libparc/parc/algol/test/test_parc_Properties.c new file mode 100644 index 00000000..994b8d8e --- /dev/null +++ b/libparc/parc/algol/test/test_parc_Properties.c @@ -0,0 +1,277 @@ +/* + * 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 "../parc_Properties.c" + +#include <LongBow/testing.h> +#include <LongBow/debugging.h> +#include <parc/algol/parc_Memory.h> +#include <parc/algol/parc_SafeMemory.h> +#include <parc/algol/parc_DisplayIndented.h> + +#include <parc/testing/parc_MemoryTesting.h> +#include <parc/testing/parc_ObjectTesting.h> + +LONGBOW_TEST_RUNNER(parc_Properties) +{ + // 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(CreateAcquireRelease); + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Specialized); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_Properties) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_Properties) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(CreateAcquireRelease) +{ + LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease); +} + +LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease) +{ + if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) { + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease) +{ + PARCProperties *instance = parcProperties_Create(); + assertNotNull(instance, "Expected non-null result from parcProperties_Create();"); + + parcObjectTesting_AssertAcquire(instance); + + parcProperties_Release(&instance); + assertNull(instance, "Expected null result from parcProperties_Release();"); +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcProperties_Compare); + LONGBOW_RUN_TEST_CASE(Global, parcProperties_Copy); + LONGBOW_RUN_TEST_CASE(Global, parcProperties_Display); + LONGBOW_RUN_TEST_CASE(Global, parcProperties_Equals); + LONGBOW_RUN_TEST_CASE(Global, parcProperties_HashCode); + LONGBOW_RUN_TEST_CASE(Global, parcProperties_IsValid); + LONGBOW_RUN_TEST_CASE(Global, parcProperties_ToJSON); + LONGBOW_RUN_TEST_CASE(Global, parcProperties_ToString); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) { + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, parcProperties_Compare) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Global, parcProperties_Copy) +{ + PARCProperties *instance = parcProperties_Create(); + PARCProperties *copy = parcProperties_Copy(instance); + assertTrue(parcProperties_Equals(instance, copy), "Expected the copy to be equal to the original"); + + parcProperties_Release(&instance); + parcProperties_Release(©); +} + +LONGBOW_TEST_CASE(Global, parcProperties_Display) +{ + PARCProperties *instance = parcProperties_Create(); + parcProperties_SetProperty(instance, "foo", "bar"); + parcProperties_SetProperty(instance, "xyzzy", "plugh"); + + parcProperties_Display(instance, 0); + parcProperties_Release(&instance); +} + +LONGBOW_TEST_CASE(Global, parcProperties_Equals) +{ + PARCProperties *x = parcProperties_Create(); + PARCProperties *y = parcProperties_Create(); + PARCProperties *z = parcProperties_Create(); + + parcObjectTesting_AssertEquals(x, y, z, NULL); + + parcProperties_Release(&x); + parcProperties_Release(&y); + parcProperties_Release(&z); +} + +LONGBOW_TEST_CASE(Global, parcProperties_HashCode) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Global, parcProperties_IsValid) +{ + PARCProperties *instance = parcProperties_Create(); + assertTrue(parcProperties_IsValid(instance), "Expected parcProperties_Create to result in a valid instance."); + + parcProperties_Release(&instance); + assertFalse(parcProperties_IsValid(instance), "Expected parcProperties_Release to result in an invalid instance."); +} + +LONGBOW_TEST_CASE(Global, parcProperties_ToJSON) +{ + PARCProperties *instance = parcProperties_Create(); + + parcProperties_SetProperty(instance, "foo", "bar"); + PARCJSON *json = parcProperties_ToJSON(instance); + + parcJSON_Release(&json); + + parcProperties_Release(&instance); +} + +LONGBOW_TEST_CASE(Global, parcProperties_ToString) +{ + PARCProperties *instance = parcProperties_Create(); + + parcProperties_SetProperty(instance, "foo", "bar"); + parcProperties_SetProperty(instance, "bar", "baz"); + char *string = parcProperties_ToString(instance); + + assertNotNull(string, "Expected non-NULL result from parcProperties_ToString"); + + parcMemory_Deallocate((void **) &string); + parcProperties_Release(&instance); +} + +LONGBOW_TEST_FIXTURE(Specialized) +{ + LONGBOW_RUN_TEST_CASE(Specialized, parcProperties_SetProperty); + LONGBOW_RUN_TEST_CASE(Specialized, parcProperties_GetProperty); + LONGBOW_RUN_TEST_CASE(Specialized, parcProperties_GetPropertyDefault); + LONGBOW_RUN_TEST_CASE(Specialized, parcProperties_GetAsBoolean_true); + LONGBOW_RUN_TEST_CASE(Specialized, parcProperties_GetAsBoolean_false); +} + +LONGBOW_TEST_FIXTURE_SETUP(Specialized) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Specialized) +{ + if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) { + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Specialized, parcProperties_SetProperty) +{ + PARCProperties *instance = parcProperties_Create(); + char *expected = "bar"; + parcProperties_SetProperty(instance, "foo", expected); + + const char *actual = parcProperties_GetProperty(instance, "foo"); + assertTrue(strcmp("bar", actual) == 0, "Expected %s, actual %s", expected, actual); + + parcProperties_Release(&instance); +} + +LONGBOW_TEST_CASE(Specialized, parcProperties_GetProperty) +{ + PARCProperties *instance = parcProperties_Create(); + char *expected = "bar"; + parcProperties_SetProperty(instance, "foo", expected); + + const char *actual = parcProperties_GetProperty(instance, "foo"); + assertTrue(strcmp("bar", actual) == 0, "Expected %s, actual %s", expected, actual); + + parcProperties_Release(&instance); +} + +LONGBOW_TEST_CASE(Specialized, parcProperties_GetPropertyDefault) +{ + PARCProperties *instance = parcProperties_Create(); + char *expected = "bar"; + parcProperties_SetProperty(instance, "foo", expected); + + const char *actual = parcProperties_GetPropertyDefault(instance, "blurfl", "defaultValue"); + assertTrue(strcmp("defaultValue", actual) == 0, "Expected %s, actual %s", "defaultValue", actual); + + parcProperties_Release(&instance); +} + +LONGBOW_TEST_CASE(Specialized, parcProperties_GetAsBoolean_true) +{ + PARCProperties *instance = parcProperties_Create(); + char *expected = "true"; + parcProperties_SetProperty(instance, "foo", expected); + + bool actual = parcProperties_GetAsBoolean(instance, "foo", false); + assertTrue(actual, "Expected true"); + + parcProperties_Release(&instance); +} + +LONGBOW_TEST_CASE(Specialized, parcProperties_GetAsBoolean_false) +{ + PARCProperties *instance = parcProperties_Create(); + char *expected = "false"; + parcProperties_SetProperty(instance, "foo", expected); + + bool actual = parcProperties_GetAsBoolean(instance, "foo", true); + assertFalse(actual, "Expected false"); + + parcProperties_Release(&instance); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Properties); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} + + diff --git a/libparc/parc/algol/test/test_parc_RandomAccessFile.c b/libparc/parc/algol/test/test_parc_RandomAccessFile.c new file mode 100644 index 00000000..796b69d8 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_RandomAccessFile.c @@ -0,0 +1,380 @@ +/* + * 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 "../parc_RandomAccessFile.c" + +#include <sys/param.h> + +#include <fcntl.h> + +#include <LongBow/testing.h> +#include <LongBow/debugging.h> +#include <parc/algol/parc_Memory.h> +#include <parc/algol/parc_SafeMemory.h> +#include <parc/algol/parc_DisplayIndented.h> + +#include <parc/testing/parc_MemoryTesting.h> +#include <parc/testing/parc_ObjectTesting.h> + +LONGBOW_TEST_RUNNER(parcRandomAccessFile_RandomAccessFile) +{ + // 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(CreateAcquireRelease); + LONGBOW_RUN_TEST_FIXTURE(Object); + LONGBOW_RUN_TEST_FIXTURE(Specialization); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parcRandomAccessFile_RandomAccessFile) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parcRandomAccessFile_RandomAccessFile) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(CreateAcquireRelease) +{ + LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease); +} + +LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease) +{ + if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) { + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease) +{ + char dirname[] = "/tmp/RandomAccessFile_XXXXXX"; + char filename[MAXPATHLEN]; + + char *temporaryDirectory = mkdtemp(dirname); + assertNotNull(temporaryDirectory, "tmp_dirname should not be null"); + sprintf(filename, "%s/tmpfile", temporaryDirectory); + + PARCFile *file = parcFile_Create(filename); + PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file); + assertNotNull(instance, "Expected non-null result from parcRandomAccessFile_Open();"); + + parcObjectTesting_AssertAcquireReleaseContract(parcRandomAccessFile_Acquire, instance); + + parcRandomAccessFile_Release(&instance); + assertNull(instance, "Expected null result from parcRandomAccessFile_Release();"); + + parcFile_Release(&file); +} + +LONGBOW_TEST_FIXTURE(Object) +{ + LONGBOW_RUN_TEST_CASE(Object, parcRandomAccessFile_Display); + // XXX: Disable this test until fixed + //LONGBOW_RUN_TEST_CASE(Object, parcRandomAccessFile_Equals); + LONGBOW_RUN_TEST_CASE(Object, parcRandomAccessFile_IsValid); + LONGBOW_RUN_TEST_CASE(Object, parcRandomAccessFile_ToJSON); + LONGBOW_RUN_TEST_CASE(Object, parcRandomAccessFile_ToString); +} + +LONGBOW_TEST_FIXTURE_SETUP(Object) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Object) +{ + if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) { + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Object, parcRandomAccessFile_Display) +{ + char dirname[] = "/tmp/RandomAccessFile_XXXXXX"; + char filename[MAXPATHLEN]; + + char *temporaryDirectory = mkdtemp(dirname); + assertNotNull(temporaryDirectory, "tmp_dirname should not be null"); + sprintf(filename, "%s/tmpfile", temporaryDirectory); + + PARCFile *file = parcFile_Create(filename); + PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file); + parcFile_Release(&file); + + parcRandomAccessFile_Display(instance, 0); + parcRandomAccessFile_Release(&instance); +} + +LONGBOW_TEST_CASE(Object, parcRandomAccessFile_Equals) +{ + char dirname[] = "/tmp/RandomAccessFile_XXXXXX"; + char filename[MAXPATHLEN]; + + char *temporaryDirectory = mkdtemp(dirname); + assertNotNull(temporaryDirectory, "tmp_dirname should not be null"); + + sprintf(filename, "%s/tmpfileX", temporaryDirectory); + PARCFile *fileX = parcFile_Create(filename); + + sprintf(filename, "%s/tmpfileY", temporaryDirectory); + PARCFile *fileY = parcFile_Create(filename); + + sprintf(filename, "%s/tmpfileZ", temporaryDirectory); + PARCFile *fileZ = parcFile_Create(filename); + + PARCRandomAccessFile *x = parcRandomAccessFile_Open(fileX); + PARCRandomAccessFile *y = parcRandomAccessFile_Open(fileY); + PARCRandomAccessFile *z = parcRandomAccessFile_Open(fileZ); + parcFile_Release(&fileX); + parcFile_Release(&fileY); + parcFile_Release(&fileZ); + + parcObjectTesting_AssertEquals(x, y, z, NULL); + + parcRandomAccessFile_Close(x); + parcRandomAccessFile_Close(y); + parcRandomAccessFile_Close(z); + + parcRandomAccessFile_Release(&x); + parcRandomAccessFile_Release(&y); + parcRandomAccessFile_Release(&z); +} + +LONGBOW_TEST_CASE(Object, parcRandomAccessFile_IsValid) +{ + char dirname[] = "/tmp/RandomAccessFile_XXXXXX"; + char filename[MAXPATHLEN]; + + char *temporaryDirectory = mkdtemp(dirname); + assertNotNull(temporaryDirectory, "tmp_dirname should not be null"); + sprintf(filename, "%s/tmpfile", temporaryDirectory); + + PARCFile *file = parcFile_Create(filename); + parcFile_CreateNewFile(file); + + PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file); + parcFile_Release(&file); + assertTrue(parcRandomAccessFile_IsValid(instance), "Expected parcRandomAccessFile_Create to result in a valid instance."); + + parcRandomAccessFile_Release(&instance); + assertFalse(parcRandomAccessFile_IsValid(instance), "Expected parcRandomAccessFile_Release to result in an invalid instance."); +} + +LONGBOW_TEST_CASE(Object, parcRandomAccessFile_ToJSON) +{ + char dirname[] = "/tmp/RandomAccessFile_XXXXXX"; + char filename[MAXPATHLEN]; + + char *temporaryDirectory = mkdtemp(dirname); + assertNotNull(temporaryDirectory, "tmp_dirname should not be null"); + sprintf(filename, "%s/tmpfile", temporaryDirectory); + + PARCFile *file = parcFile_Create(filename); + PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file); + parcFile_Release(&file); + + PARCJSON *json = parcRandomAccessFile_ToJSON(instance); + + const PARCJSONPair *pair = parcJSON_GetPairByName(json, "fname"); + PARCJSONValue *value = parcJSONPair_GetValue(pair); + PARCBuffer *buffer = parcJSONValue_GetString(value); + + char *string = parcBuffer_ToString(buffer); + assertTrue(strcmp(filename, string) == 0, "The file was stored correctly"); + + parcMemory_Deallocate(&string); + + parcJSON_Release(&json); + + parcRandomAccessFile_Release(&instance); +} + +LONGBOW_TEST_CASE(Object, parcRandomAccessFile_ToString) +{ + char dirname[] = "/tmp/RandomAccessFile_XXXXXX"; + char filename[MAXPATHLEN]; + + char *temporaryDirectory = mkdtemp(dirname); + assertNotNull(temporaryDirectory, "tmp_dirname should not be null"); + sprintf(filename, "%s/tmpfile", temporaryDirectory); + + PARCFile *file = parcFile_Create(filename); + PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file); + parcFile_Release(&file); + + char *string = parcRandomAccessFile_ToString(instance); + + assertNotNull(string, "Expected non-NULL result from parcRandomAccessFile_ToString"); + + parcMemory_Deallocate((void **) &string); + parcRandomAccessFile_Release(&instance); +} + +LONGBOW_TEST_FIXTURE(Specialization) +{ + LONGBOW_RUN_TEST_CASE(Object, parcRandomAccessFile_Read); + LONGBOW_RUN_TEST_CASE(Object, parcRandomAccessFile_Write); + LONGBOW_RUN_TEST_CASE(Object, parcRandomAccessFile_Seek); +} + +LONGBOW_TEST_FIXTURE_SETUP(Specialization) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization) +{ + if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) { + parcSafeMemory_ReportAllocation(STDOUT_FILENO); + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Object, parcRandomAccessFile_Read) +{ + char *fname = "tmpfile"; + + PARCFile *file = parcFile_Create(fname); + + parcFile_CreateNewFile(file); + FILE *fp = fopen(fname, "w"); + fseek(fp, 0, SEEK_SET); + + uint8_t data[128]; + for (int i = 0; i < 128; i++) { + data[i] = i; + } + fwrite(data, 1, 128, fp); + fclose(fp); + + PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file); + parcFile_Release(&file); + + PARCBuffer *buffer = parcBuffer_Allocate(128); + size_t numBytes = parcRandomAccessFile_Read(instance, buffer); + assertTrue(numBytes == 128, "Expected 128 bytes to be read, but got %zu", numBytes); + + parcBuffer_Flip(buffer); + uint8_t *bytes = parcBuffer_Overlay(buffer, parcBuffer_Remaining(buffer)); + assertTrue(memcmp(data, bytes, 128) == 0, "Expected buffers to be equal"); + + parcBuffer_Release(&buffer); + parcRandomAccessFile_Close(instance); + parcRandomAccessFile_Release(&instance); +} + +LONGBOW_TEST_CASE(Object, parcRandomAccessFile_Write) +{ + char *fname = "tmpfile"; + + PARCFile *file = parcFile_Create(fname); + + parcFile_CreateNewFile(file); + + uint8_t data[128]; + for (int i = 0; i < 128; i++) { + data[i] = i; + } + + PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file); + PARCBuffer *buffer = parcBuffer_Allocate(128); + parcBuffer_PutArray(buffer, 128, data); + parcBuffer_Flip(buffer); + size_t numBytes = parcRandomAccessFile_Write(instance, buffer); + assertTrue(numBytes == 128, "Expected 128 bytes to be read, but got %zu", numBytes); + parcBuffer_Release(&buffer); + + parcRandomAccessFile_Close(instance); + parcRandomAccessFile_Release(&instance); + + uint8_t bytes[128]; + FILE *fp = fopen(fname, "r"); + numBytes = fread(bytes, 1, 128, fp); + assertTrue(numBytes == 128, "Expected 128 bytes to be read, but got %zu", numBytes); + + fclose(fp); + + assertTrue(memcmp(data, bytes, 128) == 0, "Expected buffers to be equal"); + + parcFile_Release(&file); +} + +LONGBOW_TEST_CASE(Object, parcRandomAccessFile_Seek) +{ + char *fname = "tmpfile"; + + PARCFile *file = parcFile_Create(fname); + + parcFile_CreateNewFile(file); + FILE *fp = fopen(fname, "w"); + fseek(fp, 0, SEEK_SET); + + uint8_t data[128]; + for (int i = 0; i < 128; i++) { + data[i] = i; + } + fwrite(data, 1, 128, fp); + fclose(fp); + + PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file); + PARCBuffer *buffer = parcBuffer_Allocate(128); + parcRandomAccessFile_Seek(instance, 64, PARCRandomAccessFilePosition_Start); + size_t numBytes = parcRandomAccessFile_Read(instance, buffer); + assertTrue(numBytes == 64, "Expected 64 bytes to be read, but got %zu", numBytes); + + parcRandomAccessFile_Seek(instance, 0, PARCRandomAccessFilePosition_End); + parcBuffer_Flip(buffer); + numBytes = parcRandomAccessFile_Read(instance, buffer); + assertTrue(numBytes == 0, "Expected 0 bytes to be read, but got %zu", numBytes); + + parcRandomAccessFile_Seek(instance, 0, PARCRandomAccessFilePosition_Start); + parcBuffer_Flip(buffer); + numBytes = parcRandomAccessFile_Read(instance, buffer); + assertTrue(numBytes == 128, "Expected 128 bytes to be read, but got %zu", numBytes); + + parcBuffer_Release(&buffer); + parcRandomAccessFile_Close(instance); + parcRandomAccessFile_Release(&instance); + + parcFile_Release(&file); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parcRandomAccessFile_RandomAccessFile); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_ReadOnlyBuffer.c b/libparc/parc/algol/test/test_parc_ReadOnlyBuffer.c new file mode 100644 index 00000000..19e250f8 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_ReadOnlyBuffer.c @@ -0,0 +1,689 @@ +/* + * 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 "../parc_ReadOnlyBuffer.c" + +#include <stdio.h> +#include <inttypes.h> + +#include <LongBow/unit-test.h> +#include <LongBow/debugging.h> +#include <parc/algol/parc_Memory.h> +#include <parc/algol/parc_SafeMemory.h> +#include <parc/testing/parc_ObjectTesting.h> + +LONGBOW_TEST_RUNNER(parc_ReadableBuffer) +{ + // 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(Getters); + LONGBOW_RUN_TEST_FIXTURE(CreateDestroy); + LONGBOW_RUN_TEST_FIXTURE(Errors); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_ReadableBuffer) +{ + 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(parc_ReadableBuffer) +{ + return LONGBOW_STATUS_SUCCEEDED; +} +LONGBOW_TEST_FIXTURE(CreateDestroy) +{ + LONGBOW_RUN_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Create); + LONGBOW_RUN_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Allocate_AcquireRelease); +// LONGBOW_RUN_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Allocate_AcquireRelease_TooMany); + LONGBOW_RUN_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Wrap); + LONGBOW_RUN_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Wrap_NULL); + LONGBOW_RUN_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Wrap_WithOffset); +} + +LONGBOW_TEST_FIXTURE_SETUP(CreateDestroy) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(CreateDestroy) +{ + 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(CreateDestroy, parcReadOnlyBuffer_Create) +{ + PARCBuffer *buffer = parcBuffer_Allocate(10); + PARCReadOnlyBuffer *actual = parcReadOnlyBuffer_Create(buffer); + + assertTrue(parcReadOnlyBuffer_Position(actual) == 0, "Expected initial position to be 0."); + assertTrue(parcReadOnlyBuffer_Limit(actual) == 10, "Expected initial limit to be 10."); + + parcReadOnlyBuffer_Release(&actual); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Wrap_NULL) +{ + PARCReadOnlyBuffer *actual = parcReadOnlyBuffer_Create(parcBuffer_Wrap(NULL, 10, 0, 10)); + assertNull(actual, "Expected parcReadOnlyBuffer_Wrap to return NULL"); +} + +LONGBOW_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Wrap) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10); + + PARCReadOnlyBuffer *actual = parcReadOnlyBuffer_Create(buffer); + assertTrue(parcReadOnlyBuffer_Position(actual) == 0, "Expected initial position to be 0."); + assertTrue(parcReadOnlyBuffer_Limit(actual) == sizeof(array) / sizeof(array[0]), "Expected initial limit to be 10."); + + parcReadOnlyBuffer_Release(&actual); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Wrap_WithOffset) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 3, 10); + + PARCReadOnlyBuffer *actual = parcReadOnlyBuffer_Create(buffer); + parcBuffer_Release(&buffer); + assertTrue(parcReadOnlyBuffer_Capacity(actual) == 10, "Expected initial capacity to be 3."); + assertTrue(parcReadOnlyBuffer_Limit(actual) == 10, "Expected initial limit to be 3."); + assertTrue(parcReadOnlyBuffer_Position(actual) == 3, "Expected initial position to be 0."); + + parcReadOnlyBuffer_Release(&actual); +} + +LONGBOW_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Allocate_AcquireRelease) +{ + PARCBuffer *buffer = parcBuffer_Allocate(10); + + PARCReadOnlyBuffer *expected = parcReadOnlyBuffer_Create(buffer); + PARCReadOnlyBuffer *actual = parcReadOnlyBuffer_Acquire(expected); + + assertTrue(expected == actual, "Expected %p, actual %p", (void *) expected, (void *) actual); + + parcReadOnlyBuffer_Release(&expected); + assertTrue(expected == NULL, "Expected parcReadOnlyBuffer_Release to NULL the pointer."); + parcReadOnlyBuffer_Release(&actual); + assertTrue(actual == NULL, "Expected parcReadOnlyBuffer_Release to NULL the pointer."); + parcBuffer_Release(&buffer); +} + +//LONGBOW_TEST_CASE_EXPECTS(CreateDestroy, parcReadOnlyBuffer_Allocate_AcquireRelease_TooMany, .event = &LongBowTrapIllegalValue) +//{ +// PARCBuffer *buffer = parcBuffer_Allocate(10); +// PARCReadOnlyBuffer *expected = parcReadOnlyBuffer_Create(buffer); +// PARCReadOnlyBuffer *actual = parcReadOnlyBuffer_Acquire(expected); +// PARCReadOnlyBuffer *alias = actual; +// +// parcBuffer_Release(&buffer); +// parcReadOnlyBuffer_Release(&expected); +// parcReadOnlyBuffer_Release(&actual); +// parcReadOnlyBuffer_Release(&alias); // this must fail. +//} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Array); + LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_ArrayOffset); + LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Clear); + LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Copy); + LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Equals); + LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Flip); + LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_GetByte); + LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_GetArray); + LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_HasRemaining); + LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_HashCode); + LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Mark); + LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Overlay); + LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Position); + LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Remaining); + LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Rewind); + LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_SetLimit); + LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_SetLimit_TruncatePosition); + LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_SetPosition); + LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_ToString); + LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_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, parcReadOnlyBuffer_Equals) +{ + PARCReadOnlyBuffer *x = parcReadOnlyBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10); + PARCReadOnlyBuffer *y = parcReadOnlyBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10); + PARCReadOnlyBuffer *z = parcReadOnlyBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10); + PARCReadOnlyBuffer *u1 = parcReadOnlyBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10 }, 10, 0, 10); + PARCReadOnlyBuffer *u2 = parcReadOnlyBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 9, 0, 9); + PARCReadOnlyBuffer *u3 = parcReadOnlyBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 9, 0, 9); + PARCReadOnlyBuffer *u4 = parcReadOnlyBuffer_SetPosition(parcReadOnlyBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 9, 0, 9), 2); + PARCReadOnlyBuffer *u5 = parcReadOnlyBuffer_SetPosition(parcReadOnlyBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 9, 0, 9), 9); + PARCReadOnlyBuffer *u6 = parcReadOnlyBuffer_SetPosition(parcReadOnlyBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 9, 0, 9), 9); + + parcObjectTesting_AssertEqualsFunction(parcReadOnlyBuffer_Equals, x, y, z, u1, u2, u3, u4, u5, u6, NULL); + + parcReadOnlyBuffer_Release(&x); + parcReadOnlyBuffer_Release(&y); + parcReadOnlyBuffer_Release(&z); + parcReadOnlyBuffer_Release(&u1); + parcReadOnlyBuffer_Release(&u2); + parcReadOnlyBuffer_Release(&u3); + parcReadOnlyBuffer_Release(&u4); + parcReadOnlyBuffer_Release(&u5); + parcReadOnlyBuffer_Release(&u6); +} + +LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Array) +{ + uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *readWriteBuffer = parcBuffer_Wrap(expected, 10, 0, 10); + PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Create(readWriteBuffer); + parcBuffer_Release(&readWriteBuffer); + + PARCByteArray *array = parcReadOnlyBuffer_Array(buffer); + uint8_t *actual = parcByteArray_Array(array); + + parcReadOnlyBuffer_Release(&buffer); + + assertTrue(expected == actual, + "Expected %p, actual %p", + (void *) expected, (void *) actual); +} + +LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Flip) +{ + uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *buffer = parcBuffer_PutArray(parcBuffer_Allocate(10), 10, expected); + + PARCReadOnlyBuffer *actual = parcReadOnlyBuffer_Create(buffer); + + parcReadOnlyBuffer_Flip(actual); + assertTrue(parcReadOnlyBuffer_Position(actual) == 0, + "Expected position to be 0."); + assertTrue(parcReadOnlyBuffer_Limit(actual) == 10, + "Expected limit to be 10."); + + parcReadOnlyBuffer_Release(&actual); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Copy) +{ + uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *buffer = parcBuffer_PutArray(parcBuffer_Allocate(10), 10, expected); + + PARCReadOnlyBuffer *original = parcReadOnlyBuffer_Create(buffer); + + PARCReadOnlyBuffer *copy = parcReadOnlyBuffer_Copy(original); + + assertTrue(parcReadOnlyBuffer_Equals(original, copy), "Expected the copy to be equal to the original."); + + parcReadOnlyBuffer_Release(©); + parcReadOnlyBuffer_Release(&original); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Clear) +{ + uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCBuffer *buffer = parcBuffer_PutArray(parcBuffer_Allocate(10), 10, expected); + + PARCReadOnlyBuffer *actual = parcReadOnlyBuffer_Create(buffer); + assertTrue(parcReadOnlyBuffer_Position(actual) == 10, "Expected position to be 10."); + assertTrue(parcReadOnlyBuffer_Limit(actual) == 10, "Expected limit to be 10."); + + parcReadOnlyBuffer_Clear(actual); + assertTrue(parcReadOnlyBuffer_Position(actual) == 0, "Expected position to be 0."); + assertTrue(parcReadOnlyBuffer_Limit(actual) == 10, "Expected limit to be 10."); + + parcBuffer_Release(&buffer); + parcReadOnlyBuffer_Release(&actual); +} + +LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_ArrayOffset) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + size_t expected = 5; + PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, expected, 10); + + size_t actual = parcReadOnlyBuffer_ArrayOffset(buffer); + parcReadOnlyBuffer_Release(&buffer); + + assertTrue(0 == actual, + "Expected offset to be 0, actual %zu", actual); +} + +LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Position) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10); + + size_t expected = 5; + parcReadOnlyBuffer_SetPosition(buffer, expected); + + size_t actual = parcReadOnlyBuffer_Position(buffer); + + assertTrue(expected == actual, + "Expected position to be 0, actual %zu", actual); + parcReadOnlyBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Overlay) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + uint8_t expected[5] = { 5, 6, 7, 8, 9 }; + + PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10); + + size_t position = 5; + parcReadOnlyBuffer_SetPosition(buffer, position); + uint8_t *actual = parcReadOnlyBuffer_Overlay(buffer, sizeof(array) - position); + + assertTrue(memcmp(expected, actual, sizeof(expected)) == 0, + "Array contents should not be different."); + parcReadOnlyBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_SetPosition) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10); + + size_t expected = 2; + parcReadOnlyBuffer_SetPosition(buffer, expected); + size_t actual = parcReadOnlyBuffer_Position(buffer); + + assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual); + + parcReadOnlyBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_SetLimit) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10); + + size_t expected = 2; + parcReadOnlyBuffer_SetLimit(buffer, expected); + size_t actual = parcReadOnlyBuffer_Limit(buffer); + + assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual); + + parcReadOnlyBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_SetLimit_TruncatePosition) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10); + + parcReadOnlyBuffer_SetPosition(buffer, 5); + parcReadOnlyBuffer_Mark(buffer); + + size_t expected = 2; + parcReadOnlyBuffer_SetLimit(buffer, expected); + size_t actual = parcReadOnlyBuffer_Limit(buffer); + + assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual); + parcReadOnlyBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Remaining) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10); + + size_t expected = 10; + size_t actual = parcReadOnlyBuffer_Remaining(buffer); + + assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual); + parcReadOnlyBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_HasRemaining) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10); + bool actual = parcReadOnlyBuffer_HasRemaining(buffer); + + assertTrue(actual, "Expected true"); + parcReadOnlyBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Rewind) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10); + parcReadOnlyBuffer_SetPosition(buffer, 4); + size_t actual = parcReadOnlyBuffer_Position(buffer); + assertTrue(actual == 4, "Expected position to be at 4."); + + parcReadOnlyBuffer_Rewind(buffer); + + actual = parcReadOnlyBuffer_Position(buffer); + assertTrue(actual == 0, "Expected position to be at 0."); + parcReadOnlyBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Mark) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10); + + size_t expected = 2; + parcReadOnlyBuffer_SetPosition(buffer, expected); + parcReadOnlyBuffer_Mark(buffer); + parcReadOnlyBuffer_SetPosition(buffer, 4); + parcReadOnlyBuffer_Reset(buffer); + size_t actual = parcReadOnlyBuffer_Position(buffer); + + assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual); + parcReadOnlyBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_GetByte) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10); + + uint8_t actual = parcReadOnlyBuffer_GetUint8(buffer); + + assertTrue(array[0] == actual, + "Expected %d, actual %d", array[0], actual); + + parcReadOnlyBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_GetArray) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10); + + uint8_t actual[10]; + + parcReadOnlyBuffer_GetArray(buffer, actual, sizeof(actual)); + + assertTrue(memcmp(array, actual, sizeof(actual)) == 0, + "Expected arrays to be equal."); + + parcReadOnlyBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_HashCode) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + PARCBuffer *referenceBuffer = parcBuffer_Wrap(array, 10, 0, 10); + + PARCReadOnlyBuffer *buffer1 = parcReadOnlyBuffer_Wrap(array, 10, 0, 10); + + PARCReadOnlyBuffer *buffer2 = parcReadOnlyBuffer_Wrap(array, 10, 0, 10); + + uint32_t hashX = parcReadOnlyBuffer_HashCode(buffer1); + uint32_t hashY = parcReadOnlyBuffer_HashCode(buffer2); + uint32_t referenceHash = parcBuffer_HashCode(referenceBuffer); + + assertTrue(hashX == hashY, "Expected %u, actual %u", hashX, hashY); + assertTrue(hashX == referenceHash, "Expected %u, actual %u", hashX, hashY); + + parcReadOnlyBuffer_Release(&buffer2); + parcReadOnlyBuffer_Release(&buffer1); + parcBuffer_Release(&referenceBuffer); +} + +LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_ToString) +{ + uint8_t array[] = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 'x' }; + + PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, sizeof(array), 0, sizeof(array)); + + char *actual = parcReadOnlyBuffer_ToString(buffer); + + assertTrue(strcmp("hello worldx", actual) == 0, "Expected 'hello world', actual %s", actual); + + parcMemory_Deallocate((void **) &actual); + + parcReadOnlyBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Display) +{ + uint8_t array[] = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 'x' }; + + PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, sizeof(array), 0, sizeof(array)); + + parcReadOnlyBuffer_Display(buffer, 0); + + parcReadOnlyBuffer_Release(&buffer); +} + +LONGBOW_TEST_FIXTURE(Getters) +{ + LONGBOW_RUN_TEST_CASE(Getters, parcReadOnlyBuffer_GetUint8); + LONGBOW_RUN_TEST_CASE(Getters, parcReadOnlyBuffer_GetUint16); + LONGBOW_RUN_TEST_CASE(Getters, parcReadOnlyBuffer_GetUint32); + LONGBOW_RUN_TEST_CASE(Getters, parcReadOnlyBuffer_GetUint64); + LONGBOW_RUN_TEST_CASE(Getters, parcReadOnlyBuffer_GetAtIndex); +} + +LONGBOW_TEST_FIXTURE_SETUP(Getters) +{ + PARCBuffer *buffer = parcBuffer_Allocate(100); + + longBowTestCase_SetClipBoardData(testCase, buffer); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Getters) +{ + PARCBuffer *buffer = longBowTestCase_GetClipBoardData(testCase); + parcBuffer_Release(&buffer); + + 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(Getters, parcReadOnlyBuffer_GetAtIndex) +{ + PARCBuffer *buffer = parcBuffer_Allocate(sizeof(uint8_t)); + uint8_t expected = 0x12; + + parcBuffer_PutUint8(buffer, expected); + parcBuffer_Flip(buffer); + + PARCReadOnlyBuffer *readOnly = parcReadOnlyBuffer_Create(buffer); + uint8_t actual = parcReadOnlyBuffer_GetAtIndex(readOnly, 0); + + parcReadOnlyBuffer_Release(&readOnly); + parcBuffer_Release(&buffer); + assertTrue(expected == actual, "Expected %d, actual %d", expected, actual); +} + +LONGBOW_TEST_CASE(Getters, parcReadOnlyBuffer_GetUint8) +{ + PARCBuffer *buffer = parcBuffer_Allocate(sizeof(uint8_t)); + uint8_t expected = 0x12; + + parcBuffer_PutUint8(buffer, expected); + parcBuffer_Flip(buffer); + + PARCReadOnlyBuffer *readOnly = parcReadOnlyBuffer_Create(buffer); + uint8_t actual = parcReadOnlyBuffer_GetUint8(readOnly); + + parcReadOnlyBuffer_Release(&readOnly); + parcBuffer_Release(&buffer); + assertTrue(expected == actual, "Expected %d, actual %d", expected, actual); +} + +LONGBOW_TEST_CASE(Getters, parcReadOnlyBuffer_GetUint16) +{ + PARCBuffer *buffer = parcBuffer_Allocate(sizeof(uint16_t)); + uint16_t expected = 0x1234; + + parcBuffer_PutUint16(buffer, expected); + parcBuffer_Flip(buffer); + + PARCReadOnlyBuffer *readOnly = parcReadOnlyBuffer_Create(buffer); + uint16_t actual = parcReadOnlyBuffer_GetUint16(readOnly); + + parcReadOnlyBuffer_Release(&readOnly); + parcBuffer_Release(&buffer); + assertTrue(expected == actual, "Expected %d, actual %d", expected, actual); +} + +LONGBOW_TEST_CASE(Getters, parcReadOnlyBuffer_GetUint32) +{ + PARCBuffer *buffer = parcBuffer_Allocate(sizeof(uint32_t)); + uint32_t expected = 0x12345678; + + parcBuffer_PutUint32(buffer, expected); + parcBuffer_Flip(buffer); + + PARCReadOnlyBuffer *readOnly = parcReadOnlyBuffer_Create(buffer); + uint32_t actual = parcReadOnlyBuffer_GetUint32(readOnly); + + parcReadOnlyBuffer_Release(&readOnly); + parcBuffer_Release(&buffer); + assertTrue(expected == actual, "Expected %d, actual %d", expected, actual); +} + +LONGBOW_TEST_CASE(Getters, parcReadOnlyBuffer_GetUint64) +{ + PARCBuffer *buffer = parcBuffer_Allocate(sizeof(uint64_t)); + uint64_t expected = 0x1234567812345678; + + parcBuffer_PutUint64(buffer, expected); + parcBuffer_Flip(buffer); + + PARCReadOnlyBuffer *readOnly = parcReadOnlyBuffer_Create(buffer); + uint64_t actual = parcReadOnlyBuffer_GetUint64(readOnly); + + parcReadOnlyBuffer_Release(&readOnly); + parcBuffer_Release(&buffer); + assertTrue(expected == actual, "Expected %" PRIu64 ", actual %" PRIu64 "", expected, actual); +} + +LONGBOW_TEST_FIXTURE(Errors) +{ + LONGBOW_RUN_TEST_CASE(Errors, parcReadOnlyBuffer_GetByte_Underflow); + LONGBOW_RUN_TEST_CASE(Errors, parcReadOnlyBuffer_Mark_mark_exceeds_position); +} + +typedef struct parc_buffer_longbow_clipboard { + PARCReadOnlyBuffer *buffer; +} parcReadOnlyBuffer_LongBowClipBoard; + +LONGBOW_TEST_FIXTURE_SETUP(Errors) +{ + uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + parcReadOnlyBuffer_LongBowClipBoard *testData = calloc(1, sizeof(parcReadOnlyBuffer_LongBowClipBoard)); + testData->buffer = parcReadOnlyBuffer_Wrap(array, sizeof(array), 0, sizeof(array)); + + longBowTestCase_SetClipBoardData(testCase, testData); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Errors) +{ + parcReadOnlyBuffer_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase); + parcReadOnlyBuffer_Release(&testData->buffer); + free(testData); + + 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_EXPECTS(Errors, parcReadOnlyBuffer_GetByte_Underflow, .event = &LongBowTrapOutOfBounds) +{ + parcReadOnlyBuffer_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase); + PARCReadOnlyBuffer *buffer = testData->buffer; + + parcReadOnlyBuffer_SetPosition(buffer, 10); + parcReadOnlyBuffer_GetUint8(buffer); // this will fail. +} + +LONGBOW_TEST_CASE_EXPECTS(Errors, parcReadOnlyBuffer_Mark_mark_exceeds_position, .event = &LongBowAssertEvent) +{ + parcReadOnlyBuffer_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase); + PARCReadOnlyBuffer *buffer = testData->buffer; + + size_t expected = 2; + parcReadOnlyBuffer_SetPosition(buffer, expected); + parcReadOnlyBuffer_Mark(buffer); + parcReadOnlyBuffer_SetPosition(buffer, 0); + parcReadOnlyBuffer_Reset(buffer); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_ReadableBuffer); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_SafeMemory.c b/libparc/parc/algol/test/test_parc_SafeMemory.c new file mode 100644 index 00000000..53c0b3c8 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_SafeMemory.c @@ -0,0 +1,813 @@ +/* + * 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 "../parc_SafeMemory.c" + +#include <LongBow/unit-test.h> + +#include <fcntl.h> + +LONGBOW_TEST_RUNNER(safetyMemory) +{ + LONGBOW_RUN_TEST_FIXTURE(Static); + LONGBOW_RUN_TEST_FIXTURE(ReportAllocation); + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Errors); + + LONGBOW_RUN_TEST_FIXTURE(Performance); +} + +LONGBOW_TEST_RUNNER_SETUP(safetyMemory) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(safetyMemory) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Static) +{ + LONGBOW_RUN_TEST_CASE(Static, PARCSafeMemory_Report); + LONGBOW_RUN_TEST_CASE(Static, _parcSafeMemory_StateToString); + LONGBOW_RUN_TEST_CASE(Static, _parcSafeMemory_GetPrefixState_OK); + LONGBOW_RUN_TEST_CASE(Static, _parcSafeMemory_GetPrefixState_ALREADYFREE); + LONGBOW_RUN_TEST_CASE(Static, _parcSafeMemory_GetPrefixState_UNDERRUN); + LONGBOW_RUN_TEST_CASE(Static, _parcSafeMemory_FormatPrefix); + LONGBOW_RUN_TEST_CASE(Static, _computeUsableMemoryLength); +} + +LONGBOW_TEST_FIXTURE_SETUP(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Static, PARCSafeMemory_Report) +{ + size_t expectedSize = 100; + void *memory = parcSafeMemory_Allocate(expectedSize); + int fd = open("/dev/null", O_WRONLY); + _parcSafeMemory_Report(memory, fd); + close(fd); + parcSafeMemory_Deallocate(&memory); +} + +LONGBOW_TEST_CASE(Static, _parcSafeMemory_StateToString) +{ + assertNotNull(_parcSafeMemory_StateToString(PARCSafeMemoryState_OK), + "PARCSafeMemoryState_OK cannot be a NULL string."); + assertNotNull(_parcSafeMemory_StateToString(PARCSafeMemoryState_MISMATCHED), + "PARCSafeMemoryState_MISMATCHED cannot be a NULL string."); + assertNotNull(_parcSafeMemory_StateToString(PARCSafeMemoryState_UNDERRUN), + "PARCSafeMemoryState_UNDERRUN cannot be a NULL string."); + assertNotNull(_parcSafeMemory_StateToString(PARCSafeMemoryState_OVERRUN), + "PARCSafeMemoryState_OVERRUN cannot be a NULL string."); + assertNotNull(_parcSafeMemory_StateToString(PARCSafeMemoryState_NOTHINGALLOCATED), + "PARCSafeMemoryState_NOTHINGALLOCATED cannot be a NULL string."); + assertNotNull(_parcSafeMemory_StateToString(PARCSafeMemoryState_ALREADYFREE), + "PARCSafeMemoryState_ALREADYFREE cannot be a NULL string."); + assertNotNull(_parcSafeMemory_StateToString(-1), + "Garbage cannot be represented by a NULL string."); +} + +LONGBOW_TEST_CASE(Static, _parcSafeMemory_GetPrefixState_OK) +{ + size_t expectedLength = 5; + int expectedAlignment = sizeof(void *); + char origin[100]; // just some number + + void *memory = _parcSafeMemory_FormatPrefix((PARCSafeMemoryOrigin *) origin, expectedLength, expectedAlignment); + PARCSafeMemoryState actual = _parcSafeMemory_GetPrefixState(memory); + assertTrue(actual == PARCSafeMemoryState_OK, + "Expected PARCSafeMemoryState_OK, actual = %d", actual); +} + +LONGBOW_TEST_CASE(Static, _parcSafeMemory_GetPrefixState_ALREADYFREE) +{ + PARCSafeMemoryUsable *usable = parcSafeMemory_Allocate(10); + PARCSafeMemoryUsable *saved = usable; + + parcSafeMemory_Deallocate((void **) &usable); + + PARCSafeMemoryState actual = _parcSafeMemory_GetPrefixState(saved); + assertTrue(actual == PARCSafeMemoryState_ALREADYFREE, + "Expected PARCSafeMemoryState_ALREADYFREE, actual = %d", actual); +} + +LONGBOW_TEST_CASE(Static, _parcSafeMemory_GetPrefixState_UNDERRUN) +{ + char *usable = parcSafeMemory_Allocate(10); + + char savedByte = usable[-1]; + usable[-1] = 0; + + PARCSafeMemoryState actual = _parcSafeMemory_GetPrefixState((PARCSafeMemoryUsable *) usable); + assertTrue(actual == PARCSafeMemoryState_UNDERRUN, + "Expected PARCSafeMemoryState_UNDERRUN, actual = %d", actual); + usable[-1] = savedByte; + parcSafeMemory_Deallocate((void **) &usable); +} + +LONGBOW_TEST_CASE(Static, _parcSafeMemory_FormatPrefix) +{ + size_t expectedLength = 5; + int expectedAlignment = sizeof(void *) - 1; + char base[100]; // just some number + void *memory = _parcSafeMemory_FormatPrefix((PARCSafeMemoryOrigin *) base, expectedLength, expectedAlignment); + + assertNull(memory, + "Expected _parcSafeMemory_FormatPrefix to return NULL for bad alignment specification."); +} + +LONGBOW_TEST_CASE(Static, _computeUsableMemoryLength) +{ + size_t actual = _computeUsableMemoryLength(100, sizeof(void *)); + + // The result must be >= to the requested length and an even multiple of sizeof(void *) + assertTrue(actual >= 100 && (actual % sizeof(void *)) == 0, + "Expected the result to be >= to the requested length and an even multiple of sizeof(void *)"); +} + +LONGBOW_TEST_FIXTURE(ReportAllocation) +{ + LONGBOW_RUN_TEST_CASE(ReportAllocation, parcSafeMemory_ReportAllocation_Empty); + LONGBOW_RUN_TEST_CASE(ReportAllocation, parcSafeMemory_ReportAllocation_One); + LONGBOW_RUN_TEST_CASE(ReportAllocation, parcSafeMemory_ReportAllocation_Deallocated); +} + +LONGBOW_TEST_CASE(ReportAllocation, parcSafeMemory_ReportAllocation_Empty) +{ + _parcSafeMemory_DeallocateAll(); + int fd = open("/dev/null", O_WRONLY); + size_t result = parcSafeMemory_ReportAllocation(fd); + close(fd); + assertTrue(result == 0, "Expected 0, was %zd", result); +} + +LONGBOW_TEST_CASE(ReportAllocation, parcSafeMemory_ReportAllocation_One) +{ + void *memory; + size_t size = 100; + + memory = parcSafeMemory_Allocate(size); + + int fd = open("/dev/null", O_WRONLY); + size_t result = parcSafeMemory_ReportAllocation(fd); + close(fd); + assertTrue(result == 1, "Expected 1, was %zd", result); + + parcSafeMemory_Deallocate(&memory); +} + +LONGBOW_TEST_CASE(ReportAllocation, parcSafeMemory_ReportAllocation_Deallocated) +{ + size_t size = 100; + void *memory = parcSafeMemory_Allocate(size); + assertTrue(parcSafeMemory_Outstanding() != 0, "No memory allocated!"); + PARCSafeMemoryState state = _parcSafeMemory_GetState(memory); + parcSafeMemory_Deallocate(&memory); + assertTrue(state == PARCSafeMemoryState_OK, "Expected uncorrupted memory."); + + int fd = open("/dev/null", O_WRONLY); + size_t result = parcSafeMemory_ReportAllocation(fd); + close(fd); + + assertTrue(result == 0, "Expected 0, was %zd", result); +} + +LONGBOW_TEST_FIXTURE_SETUP(ReportAllocation) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(ReportAllocation) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Allocate); + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_MemAlign); + + LONGBOW_RUN_TEST_CASE(Global, PARCSafeMemory_Realloc_Larger); + LONGBOW_RUN_TEST_CASE(Global, PARCSafeMemory_Realloc_Smaller); + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Reallocate_Zero); + LONGBOW_RUN_TEST_CASE(Global, PARCSafeMemory_Validate); + + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Allocate_BadAlignment); + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Allocate_BadSize); + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_AllocateAndClear); + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Reallocate); + + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Deallocate_NothingAllocated); + + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_IsValid_True); + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_IsValid_False); + + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Display); + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Display_NULL); + + LONGBOW_RUN_TEST_CASE(Global, compute_prefix_length); + LONGBOW_RUN_TEST_CASE(Global, _parcSafeMemory_FormatMemory); + LONGBOW_RUN_TEST_CASE(Global, memory_prefix_format); + LONGBOW_RUN_TEST_CASE(Global, memory_prefix_validate); + LONGBOW_RUN_TEST_CASE(Global, memory_suffix_format); + LONGBOW_RUN_TEST_CASE(Global, memory_suffix_validate); + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_StringDuplicate); + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_StringDuplicate_Long); + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_StringDuplicate_Short); + LONGBOW_RUN_TEST_CASE(Global, validateAlignment); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + assertTrue(parcSafeMemory_Outstanding() == 0, "Expected 0 outstanding allocations") + { + printf("Leaking test case: %s", longBowTestCase_GetName(testCase)); + } + return LONGBOW_STATUS_SUCCEEDED; +} + + +LONGBOW_TEST_CASE(Global, validateAlignment) +{ + assertTrue(_alignmentIsValid(sizeof(void *)), + "Expected alignment of sizeof(void *) failed."); + assertTrue(_alignmentIsValid(16), + "Expected alignment of 16 failed."); +} + +LONGBOW_TEST_CASE(Global, compute_prefix_length) +{ + // Test that the result is a multiple of the alignment value and greater than the size of _MemoryPrefix. + for (int i = 0; i < 9; i++) { + size_t alignment = 1 << i; + size_t actual = _computePrefixLength(alignment); + assertTrue((actual & (alignment - 1)) == 0, + "Alignment needs to be a multiple of %zd", alignment); + } +} + +LONGBOW_TEST_CASE(Global, memory_prefix_format) +{ + size_t expectedLength = 5; + int expectedAlignment = sizeof(void *); + char base[100]; + void *memory = _parcSafeMemory_FormatPrefix((PARCSafeMemoryOrigin *) base, expectedLength, expectedAlignment); + + _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix(memory); + + assertAligned(prefix, sizeof(void *), + "prefix address %p is not aligned to %d", + memory, expectedAlignment); + assertAligned(memory, expectedAlignment, + "memory address %p is not aligned to %d", + memory, expectedAlignment); + + assertTrue((void *) prefix >= (void *) base, + "Expected >= %p, actual %p", (void *) base, (void *) prefix); + assertTrue(_parcSafeMemory_PrefixMagic == prefix->magic, + "Prefix magic is wrong."); + assertTrue(expectedLength == prefix->requestedLength, + "Expected length %zd, actual %zd", expectedLength, prefix->requestedLength); + assertTrue(expectedAlignment == prefix->alignment, + "Expected alignment %d, actual %zu", + expectedAlignment, prefix->alignment); + assertTrue(_parcSafeMemory_Guard == prefix->guard, + "Prefix guard is wrong."); +} + +LONGBOW_TEST_CASE(Global, memory_suffix_format) +{ + size_t expectedLength = 5; + int expectedAlignment = sizeof(void *); + char base[100]; + void *memory = _parcSafeMemory_FormatPrefix((PARCSafeMemoryOrigin *) base, expectedLength, expectedAlignment); + + _MemorySuffix *suffix = _parcSafeMemory_FormatSuffix(memory); + assertAligned(suffix, sizeof(void *), "suffix pointer is not aligned to %zu", sizeof(void*)); +} + +LONGBOW_TEST_CASE(Global, memory_suffix_validate) +{ + size_t expectedLength = 5; + int expectedAlignment = sizeof(void *); + char base[100]; + void *memory = _parcSafeMemory_FormatPrefix((PARCSafeMemoryOrigin *) base, expectedLength, expectedAlignment); + + _MemorySuffix *suffix = _parcSafeMemory_FormatSuffix(memory); + assertAligned(suffix, sizeof(void *), + "suffix pointer is not aligned to %zu", sizeof(void*)); + + PARCSafeMemoryState suffixState = _parcSafeMemory_GetSuffixState(memory); + assertTrue(suffixState == PARCSafeMemoryState_OK, + "Expected PARCSafeMemoryState_OK suffix state, actual %s", _parcSafeMemory_StateToString(suffixState)); +} + +LONGBOW_TEST_CASE(Global, memory_prefix_validate) +{ + size_t expectedLength = 5; + int expectedAlignment = sizeof(void *); + char base[100]; + + void *memory = _parcSafeMemory_FormatPrefix((PARCSafeMemoryOrigin *) base, expectedLength, expectedAlignment); + PARCSafeMemoryState actual = _parcSafeMemory_GetPrefixState(memory); + assertTrue(actual == PARCSafeMemoryState_OK, + "Expected valid prefix, actual = %d", actual); +} + +LONGBOW_TEST_CASE(Global, _parcSafeMemory_FormatMemory) +{ + size_t expectedLength = 5; + int expectedAlignment = sizeof(void *); + char base[100]; + + void *memory = _parcSafeMemory_FormatMemory((PARCSafeMemoryOrigin *) base, expectedLength, expectedAlignment); + + PARCSafeMemoryState state = _parcSafeMemory_GetState(memory); + + assertTrue(state == PARCSafeMemoryState_OK, + "Memory did not validate. Actual %d", state); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_Allocate) +{ + void *memory; + size_t size = 100; + + memory = parcSafeMemory_Allocate(size); + + assertTrue(memory != NULL, + "Expected non-NULL return."); + + assertTrue((_parcSafeMemory_GetPrefixState(memory)) == PARCSafeMemoryState_OK, + "Prefix did not validate."); + parcSafeMemory_Deallocate(&memory); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_MemAlign) +{ + void *memory; + size_t size = 100; + + int failure = parcSafeMemory_MemAlign(&memory, sizeof(void *), size); + assertTrue(failure == 0, + "parcSafeMemory_MemAlign failed: %d", failure); + + assertTrue(memory != NULL, + "Expected non-NULL return."); + + assertTrue((_parcSafeMemory_GetPrefixState(memory)) == PARCSafeMemoryState_OK, + "Prefix did not validate."); + parcSafeMemory_Deallocate(&memory); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_ReportAllocation) +{ + void *memory; + size_t size = 100; + + memory = parcSafeMemory_Allocate(size); + assertTrue(memory != NULL, "Expected non-NULL return."); + PARCSafeMemoryState prefixState = _parcSafeMemory_GetPrefixState(memory); + assertTrue(prefixState == PARCSafeMemoryState_OK, + "Prefix did not validate."); + + parcSafeMemory_ReportAllocation(1); +} + +LONGBOW_TEST_CASE(Global, PARCSafeMemory_Validate) +{ + void *memory; + size_t size = 100; + + memory = parcSafeMemory_Allocate(size); + + assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK, + "Memory did not validate."); + parcSafeMemory_Deallocate(&memory); +} + +LONGBOW_TEST_CASE(Global, PARCSafeMemory_Realloc_Larger) +{ + void *memory = parcSafeMemory_Allocate(100); + + for (unsigned char i = 0; i < 100; i++) { + ((unsigned char *) memory)[i] = i; + } + + assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK, + "Expected memory to be OK."); + + size_t expectedLength = 100 + 1; + unsigned char *newMemory = parcSafeMemory_Reallocate(memory, expectedLength); + + assertTrue(_parcSafeMemory_GetState((PARCSafeMemoryUsable *) memory) != PARCSafeMemoryState_OK, + "Expected original memory to NOT be OK."); + assertTrue(_parcSafeMemory_GetState((PARCSafeMemoryUsable *) newMemory) == PARCSafeMemoryState_OK, + "Expected new memory to be OK."); + + _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix((PARCSafeMemoryUsable *) newMemory); + assertTrue(prefix->requestedLength == expectedLength, + "Prefix Expected length %zd, actual %zd", expectedLength, prefix->requestedLength); + + for (int i = 0; i < 100; i++) { + assertTrue(((unsigned char *) newMemory)[i] == i, + "PARCSafeMemory_Realloc did not copy old memory correctly"); + } + + assertTrue(parcSafeMemory_Outstanding() != 0, + "No memory allocated!"); + PARCSafeMemoryState state = _parcSafeMemory_GetState((PARCSafeMemoryUsable *) newMemory); + parcSafeMemory_Deallocate((void **) &newMemory); + assertTrue(state == PARCSafeMemoryState_OK, + "Expected PARCSafeMemory_Deallocate of new memory to be OK, actual =%d", state); + assertTrue(_parcSafeMemory_GetState(memory) != PARCSafeMemoryState_OK, + "Expected old memory to be invalid."); +} + +LONGBOW_TEST_CASE(Global, PARCSafeMemory_Realloc_Smaller) +{ + void *memory = parcSafeMemory_Allocate(100); + assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK, + "Memory did not validate."); + + for (unsigned char i = 0; i < 100; i++) { + ((unsigned char *) memory)[i] = i; + } + + size_t expectedLength = 100 - 1; + unsigned char *newMemory = parcSafeMemory_Reallocate(memory, expectedLength); + + assertTrue(_parcSafeMemory_GetState(memory) != PARCSafeMemoryState_OK, + "Expected original memory to NOT be OK."); + assertTrue(_parcSafeMemory_GetState((PARCSafeMemoryUsable *) newMemory) == PARCSafeMemoryState_OK, + "Expected new memory to be OK."); + + _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix((PARCSafeMemoryUsable *) newMemory); + assertTrue(prefix->requestedLength == expectedLength, + "Prefix Expected length %zd, actual %zd", expectedLength, prefix->requestedLength); + + for (int i = 0; i < expectedLength; i++) { + assertTrue(((unsigned char *) newMemory)[i] == i, + "PARCSafeMemory_Realloc did not copy correctly"); + } + + assertTrue(parcSafeMemory_Outstanding() != 0, + "No memory allocated!"); + PARCSafeMemoryState state = _parcSafeMemory_GetState((PARCSafeMemoryUsable *) newMemory); + parcSafeMemory_Deallocate((void **) &newMemory); + assertTrue(state == PARCSafeMemoryState_OK, + "Expected PARCSafeMemory_Deallocate of new memory to be OK, actual =%d", state); + assertTrue(_parcSafeMemory_GetState(memory) != PARCSafeMemoryState_OK, + "Expected old memory to be invalid."); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_Reallocate_Zero) +{ + void *memory = parcSafeMemory_Allocate(100); + assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK, + "Memory did not validate."); + + for (unsigned char i = 0; i < 100; i++) { + ((unsigned char *) memory)[i] = i; + } + + size_t expectedLength = 0; + unsigned char *newMemory = parcSafeMemory_Reallocate(memory, expectedLength); + + assertTrue(newMemory == NULL, + "Expected NULL, actual %p", (void *) newMemory); + + parcSafeMemory_Deallocate(&memory); + assertNull(memory, + "Expected memory pointer to be NULL."); +} + +LONGBOW_TEST_CASE(Global, PARCSafeMemory_DoubleFree) +{ + size_t expectedSize = 100; + + void *memory = parcSafeMemory_Allocate(expectedSize); + assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK, + "Memory did not validate."); + + for (unsigned char i = 0; i < expectedSize; i++) { + ((unsigned char *) memory)[i] = i; + } + + assertTrue(parcSafeMemory_Outstanding() != 0, + "No memory allocated!"); + PARCSafeMemoryState state = _parcSafeMemory_GetState(memory); + parcSafeMemory_Deallocate(&memory); + assertTrue(state == PARCSafeMemoryState_OK, + "Expected memory to validate"); + assertTrue(parcSafeMemory_Outstanding() != 0, + "No memory allocated!"); + state = _parcSafeMemory_GetState(memory); + parcSafeMemory_Deallocate(&memory); + assertTrue(state == PARCSafeMemoryState_UNDERRUN, + "Expected memory to be underrun (double free)."); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_StringDuplicate) +{ + char *string = "hello world"; + char *actual = parcSafeMemory_StringDuplicate(string, strlen(string)); + + assertTrue(strcmp(string, actual) == 0, + "Expected %s, actual %s", string, actual); + parcSafeMemory_Deallocate((void **) &actual); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_StringDuplicate_Long) +{ + char *string = "hello world"; + char *actual = parcSafeMemory_StringDuplicate(string, SIZE_MAX); + + assertTrue(strcmp(string, actual) == 0, + "Expected %s, actual %s", string, actual); + parcSafeMemory_Deallocate((void **) &actual); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_StringDuplicate_Short) +{ + char *string = "hello world"; + char *expected = "hello"; + char *actual = parcSafeMemory_StringDuplicate(string, 5); + + assertTrue(strcmp(expected, actual) == 0, + "Expected %s, actual %s", expected, actual); + parcSafeMemory_Deallocate((void **) &actual); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_Allocate_BadAlignment) +{ + void *result; + size_t alignment = 3; + size_t size = 100; + + int failure = parcSafeMemory_MemAlign(&result, alignment, size); + assertTrue(failure == EINVAL, + "parcSafeMemory_MemAlign failed to report bad aligment specification"); + assertTrue(parcSafeMemory_Outstanding() == 0, + "Expected 0 outstanding allocations, actual %d", parcSafeMemory_Outstanding()); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_Allocate_BadSize) +{ + void *result; + size_t alignment = sizeof(void *); + size_t size = 0; + + int failure = parcSafeMemory_MemAlign(&result, alignment, size); + assertTrue(failure == EINVAL, + "parcSafeMemory_MemAlign failed to report bad aligment specification"); + assertTrue(parcSafeMemory_Outstanding() == 0, + "Expected 0 outstanding allocation, actual %d", parcSafeMemory_Outstanding()); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_AllocateAndClear) +{ + void *result; + size_t size = 100; + + result = parcSafeMemory_AllocateAndClear(size); + assertNotNull(result, + "parcSafeMemory_AllocateAndClear failed: NULL result."); + + for (size_t i = 0; i < size; i++) { + assertTrue(((char *) result)[i] == 0, + "parcSafeMemory_AllocateAndClear failed to zero memory at index %zd", i); + } + assertTrue(parcSafeMemory_Outstanding() == 1, + "Expected 1 outstanding allocation, actual %d", parcSafeMemory_Outstanding()); + parcSafeMemory_Deallocate(&result); + assertTrue(parcSafeMemory_Outstanding() == 0, + "Expected 0 outstanding allocation, actual %d", parcSafeMemory_Outstanding()); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_Reallocate) +{ + size_t size = 100; + + void *result = parcSafeMemory_AllocateAndClear(size); + assertNotNull(result, + "parcSafeMemory_Allocate failed: NULL."); + + for (size_t i = 0; i < size; i++) { + assertTrue(((char *) result)[i] == 0, + "parcSafeMemory_AllocateAndClear failed to zero memory at index %zd", i); + } + + result = parcSafeMemory_Reallocate(result, size * 2); + + assertTrue(parcSafeMemory_Outstanding() == 1, + "Expected 1 outstanding allocation, actual %d", parcSafeMemory_Outstanding()); + parcSafeMemory_Deallocate(&result); + assertTrue(parcSafeMemory_Outstanding() == 0, + "Expected 0 outstanding allocations, actual %d", parcSafeMemory_Outstanding()); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_Deallocate_NothingAllocated) +{ + void *result = 0; + + parcSafeMemory_Deallocate(&result); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_IsValid_True) +{ + void *result = parcSafeMemory_AllocateAndClear(5); + + assertTrue(parcSafeMemory_IsValid(result), "Expected properly allocated memory to be valid PARC Safe Memory."); + + parcSafeMemory_Deallocate(&result); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_IsValid_False) +{ + char *memory[10]; + + assertFalse(parcSafeMemory_IsValid(memory), "Expected improperly allocated memory to be invalid PARC Safe Memory."); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_Display) +{ + void *result = parcSafeMemory_AllocateAndClear(5); + + parcSafeMemory_Display(result, 0); + parcSafeMemory_Deallocate(&result); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_Display_NULL) +{ + parcSafeMemory_Display(NULL, 0); +} + +LONGBOW_TEST_FIXTURE(Errors) +{ + LONGBOW_RUN_TEST_CASE(Errors, parcSafeMemory_Reallocate_NULL); + LONGBOW_RUN_TEST_CASE(Errors, PARCSafeMemory_Deallocate_Overrun); + LONGBOW_RUN_TEST_CASE(Errors, PARCSafeMemory_Deallocate_Underrun); +} + +LONGBOW_TEST_FIXTURE_SETUP(Errors) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Errors) +{ + // The tests purposefully wreck the various per-allocation accounting structures for the allocated memory in order to test for + // properly catching the overrun, underrun or other damage. + // As a result any cleanup of allocated memory is not possible, so these tests leak allocated memory. + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Errors, parcSafeMemory_Reallocate_NULL) +{ + void *result = NULL; + size_t size = 100; + + result = parcSafeMemory_Reallocate(result, size * 2); + + assertTrue(parcSafeMemory_Outstanding() == 1, + "Expected 1 outstanding allocation, actual %d", parcSafeMemory_Outstanding()); + parcSafeMemory_Deallocate(&result); + assertTrue(parcSafeMemory_Outstanding() == 0, + "Expected 0 outstanding allocations, actual %d", parcSafeMemory_Outstanding()); +} + +LONGBOW_TEST_CASE_EXPECTS(Errors, PARCSafeMemory_Deallocate_Underrun, .event = &LongBowTrapUnexpectedStateEvent) +{ + size_t expectedSize = sizeof(void *) * 2; + void *memory = parcSafeMemory_Allocate(expectedSize); + assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK, + "Memory did not validate."); + + for (int i = -2; i < (int) expectedSize; i++) { + ((unsigned char *) memory)[i] = (unsigned char) i; + } + + assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_UNDERRUN, + "Memory did not underrun."); + + assertTrue(parcSafeMemory_Outstanding() != 0, + "No memory allocated!"); + PARCSafeMemoryState state = _parcSafeMemory_GetState(memory); + parcSafeMemory_Deallocate(&memory); + + assertTrue(state == PARCSafeMemoryState_UNDERRUN, + "Expected memory to be underrun"); +} + +LONGBOW_TEST_CASE_EXPECTS(Errors, PARCSafeMemory_Deallocate_Overrun, .event = &LongBowTrapUnexpectedStateEvent) +{ + size_t expectedSize = 100; + void *memory = parcSafeMemory_Allocate(expectedSize); + assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK, + "Memory did not validate."); + + for (unsigned char i = 0; i < expectedSize + 5; i++) { + ((unsigned char *) memory)[i] = i; + } + + assertTrue(parcSafeMemory_Outstanding() != 0, + "No memory allocated!"); + assertTrue(_parcSafeMemory_GetState(memory) != PARCSafeMemoryState_OK, + "Expected not OK, actual %s", _parcSafeMemory_StateToString(_parcSafeMemory_GetState(memory))); + // this is expected to fail + parcSafeMemory_Deallocate(&memory); +} + +LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false) +{ + LONGBOW_RUN_TEST_CASE(Performance, parcSafeMemory_AllocateDeallocate_1000000_WorstCase); + LONGBOW_RUN_TEST_CASE(Performance, parcSafeMemory_AllocateDeallocate_1000000_BestCase); + + LONGBOW_RUN_TEST_CASE(Performance, _computeUsableMemoryLength); +} + +LONGBOW_TEST_FIXTURE_SETUP(Performance) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Performance) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +void *memory[1000000]; + +LONGBOW_TEST_CASE(Performance, parcSafeMemory_AllocateDeallocate_1000000_WorstCase) +{ + size_t size = 100; + + for (int i = 0; i < sizeof(memory) / sizeof(memory[0]); i++) { + memory[i] = parcSafeMemory_Allocate(size); + } + for (int i = 0; i < sizeof(memory) / sizeof(memory[0]); i++) { + parcSafeMemory_Deallocate(&memory[i]); + } +} + +LONGBOW_TEST_CASE(Performance, parcSafeMemory_AllocateDeallocate_1000000_BestCase) +{ + size_t size = 100; + + for (int i = 0; i < sizeof(memory) / sizeof(memory[0]); i++) { + memory[i] = parcSafeMemory_Allocate(size); + } + + int i = sizeof(memory) / sizeof(memory[0]); + do { + i--; + parcSafeMemory_Deallocate(&memory[i]); + } while (i > 0); +} + +LONGBOW_TEST_CASE(Performance, _computeUsableMemoryLength) +{ + for (int i = 0; i < 100000000; i++) { + size_t alignment = sizeof(void *); + size_t requestedLength = 10; + _computeUsableMemoryLength(requestedLength, alignment); + } +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(safetyMemory); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_SortedList.c b/libparc/parc/algol/test/test_parc_SortedList.c new file mode 100644 index 00000000..f0445d86 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_SortedList.c @@ -0,0 +1,510 @@ +/* + * 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 "../parc_SortedList.c" + +#include <LongBow/testing.h> +#include <LongBow/debugging.h> +#include <parc/algol/parc_Memory.h> +#include <parc/algol/parc_SafeMemory.h> +#include <parc/algol/parc_DisplayIndented.h> + +#include <parc/testing/parc_MemoryTesting.h> +#include <parc/testing/parc_ObjectTesting.h> + +LONGBOW_TEST_RUNNER(parc_SortedList) +{ + // 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(CreateAcquireRelease); + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Specialization); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_SortedList) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_SortedList) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(CreateAcquireRelease) +{ + LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease); + LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateCompare); +} + +LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease) +{ + if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) { + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease) +{ + PARCSortedList *instance = parcSortedList_Create(); + assertNotNull(instance, "Expected non-null result from parcSortedList_Create();"); + + parcObjectTesting_AssertAcquire(instance); + + parcSortedList_Release(&instance); + assertNull(instance, "Expected null result from parcSortedList_Release();"); +} + +// A signum function to compare two PARCBuffers by length of buffer. +static int +_compareTwoBuffersByLength(const PARCObject *buf1, const PARCObject *buf2) +{ + size_t size1 = parcBuffer_Limit((PARCBuffer *) buf1); + size_t size2 = parcBuffer_Limit((PARCBuffer *) buf2); + + if (size1 > size2) { + return 1; + } else if (size2 > size1) { + return -1; + } + return 0; +} + +LONGBOW_TEST_CASE(CreateAcquireRelease, CreateCompare) +{ + PARCSortedList *instance = parcSortedList_CreateCompare(_compareTwoBuffersByLength); + + PARCBuffer *buf1 = parcBuffer_WrapCString("medium long"); + PARCBuffer *buf2 = parcBuffer_WrapCString("somewhat longer"); + PARCBuffer *buf3 = parcBuffer_WrapCString("short"); + + parcSortedList_Add(instance, buf1); + parcSortedList_Add(instance, buf2); + parcSortedList_Add(instance, buf3); + + PARCBuffer *test = parcSortedList_GetAtIndex(instance, 0); + assertTrue(test == buf3, "Expected the shortes buffer first"); + + test = parcSortedList_GetAtIndex(instance, 1); + assertTrue(test == buf1, "Expected the medium length buffer second"); + + test = parcSortedList_GetAtIndex(instance, 2); + assertTrue(test == buf2, "Expected the longest buffer last"); + + parcBuffer_Release(&buf1); + parcBuffer_Release(&buf2); + parcBuffer_Release(&buf3); + + parcSortedList_Release(&instance); +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcSortedList_Copy); + LONGBOW_RUN_TEST_CASE(Global, parcSortedList_Display); + LONGBOW_RUN_TEST_CASE(Global, parcSortedList_Equals); + LONGBOW_RUN_TEST_CASE(Global, parcSortedList_HashCode); + LONGBOW_RUN_TEST_CASE(Global, parcSortedList_IsValid); + LONGBOW_RUN_TEST_CASE(Global, parcSortedList_ToJSON); + LONGBOW_RUN_TEST_CASE(Global, parcSortedList_ToString); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) { + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, parcSortedList_Copy) +{ + PARCSortedList *instance = parcSortedList_Create(); + PARCSortedList *copy = parcSortedList_Copy(instance); + assertTrue(parcSortedList_Equals(instance, copy), "Expected the copy to be equal to the original"); + + parcSortedList_Release(&instance); + parcSortedList_Release(©); +} + +LONGBOW_TEST_CASE(Global, parcSortedList_Display) +{ + PARCSortedList *instance = parcSortedList_Create(); + parcSortedList_Display(instance, 0); + parcSortedList_Release(&instance); +} + +LONGBOW_TEST_CASE(Global, parcSortedList_Equals) +{ + PARCSortedList *x = parcSortedList_Create(); + PARCSortedList *y = parcSortedList_Create(); + PARCSortedList *z = parcSortedList_Create(); + + parcObjectTesting_AssertEquals(x, y, z, NULL); + + parcSortedList_Release(&x); + parcSortedList_Release(&y); + parcSortedList_Release(&z); +} + +LONGBOW_TEST_CASE(Global, parcSortedList_HashCode) +{ + PARCSortedList *x = parcSortedList_Create(); + PARCSortedList *y = parcSortedList_Create(); + + parcObjectTesting_AssertHashCode(x, y); + + parcSortedList_Release(&x); + parcSortedList_Release(&y); +} + +LONGBOW_TEST_CASE(Global, parcSortedList_IsValid) +{ + PARCSortedList *instance = parcSortedList_Create(); + assertTrue(parcSortedList_IsValid(instance), "Expected parcSortedList_Create to result in a valid instance."); + + parcSortedList_Release(&instance); + assertFalse(parcSortedList_IsValid(instance), "Expected parcSortedList_Release to result in an invalid instance."); +} + +LONGBOW_TEST_CASE(Global, parcSortedList_ToJSON) +{ + PARCSortedList *instance = parcSortedList_Create(); + + PARCJSON *json = parcSortedList_ToJSON(instance); + + parcJSON_Release(&json); + + parcSortedList_Release(&instance); +} + +LONGBOW_TEST_CASE(Global, parcSortedList_ToString) +{ + PARCSortedList *instance = parcSortedList_Create(); + + char *string = parcSortedList_ToString(instance); + + assertNotNull(string, "Expected non-NULL result from parcSortedList_ToString"); + + parcMemory_Deallocate((void **) &string); + parcSortedList_Release(&instance); +} + +LONGBOW_TEST_FIXTURE(Specialization) +{ + LONGBOW_RUN_TEST_CASE(Specialization, parcSortedList_Add); + LONGBOW_RUN_TEST_CASE(Specialization, parcSortedList_Remove); + LONGBOW_RUN_TEST_CASE(Specialization, parcSortedList_GetAtIndex); + LONGBOW_RUN_TEST_CASE(Specialization, parcSortedList_GetFirst); + LONGBOW_RUN_TEST_CASE(Specialization, parcSortedList_GetLast); + + LONGBOW_RUN_TEST_CASE(Specialization, parcSortedList_RemoveFirst); + LONGBOW_RUN_TEST_CASE(Specialization, parcSortedList_RemoveFirst_SingleElement); + LONGBOW_RUN_TEST_CASE(Specialization, parcSortedList_RemoveLast); +} + +LONGBOW_TEST_FIXTURE_SETUP(Specialization) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization) +{ + if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) { + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +static void +dump(PARCSortedList *i) +{ + PARCIterator *iterator = parcSortedList_CreateIterator(i); + while (parcIterator_HasNext(iterator)) { + PARCBuffer *buffer = parcIterator_Next(iterator); + parcBuffer_Display(buffer, 0); + } + + parcIterator_Release(&iterator); +} + +LONGBOW_TEST_CASE(Specialization, parcSortedList_Add) +{ + PARCSortedList *instance = parcSortedList_Create(); + PARCBuffer *element1 = parcBuffer_WrapCString("1"); + PARCBuffer *element2 = parcBuffer_WrapCString("2"); + PARCBuffer *element3 = parcBuffer_WrapCString("3"); + PARCBuffer *element4 = parcBuffer_WrapCString("4"); + PARCBuffer *element7 = parcBuffer_WrapCString("7"); + PARCBuffer *element6 = parcBuffer_WrapCString("6"); + PARCBuffer *element5 = parcBuffer_WrapCString("5"); + PARCBuffer *element8 = parcBuffer_WrapCString("8"); + + parcSortedList_Add(instance, element2); + parcSortedList_Display(instance, 0); + parcSortedList_Add(instance, element8); + parcSortedList_Display(instance, 0); + parcSortedList_Add(instance, element3); + parcSortedList_Display(instance, 0); + parcSortedList_Add(instance, element4); + parcSortedList_Display(instance, 0); + parcSortedList_Add(instance, element7); + parcSortedList_Display(instance, 0); + parcSortedList_Add(instance, element6); + parcSortedList_Display(instance, 0); + parcSortedList_Add(instance, element5); + parcSortedList_Display(instance, 0); + parcSortedList_Add(instance, element1); + parcSortedList_Display(instance, 0); + parcSortedList_Add(instance, element6); + parcSortedList_Display(instance, 0); + + dump(instance); + + parcBuffer_Release(&element1); + parcBuffer_Release(&element2); + parcBuffer_Release(&element3); + parcBuffer_Release(&element4); + parcBuffer_Release(&element5); + parcBuffer_Release(&element6); + parcBuffer_Release(&element7); + parcBuffer_Release(&element8); + parcSortedList_Release(&instance); +} + +LONGBOW_TEST_CASE(Specialization, parcSortedList_Remove) +{ + PARCSortedList *instance = parcSortedList_Create(); + PARCBuffer *element1 = parcBuffer_WrapCString("1"); + PARCBuffer *element2 = parcBuffer_WrapCString("2"); + PARCBuffer *element3 = parcBuffer_WrapCString("3"); + PARCBuffer *element4 = parcBuffer_WrapCString("4"); + PARCBuffer *element7 = parcBuffer_WrapCString("7"); + PARCBuffer *element6 = parcBuffer_WrapCString("6"); + PARCBuffer *element5 = parcBuffer_WrapCString("5"); + PARCBuffer *element8 = parcBuffer_WrapCString("8"); + + parcSortedList_Add(instance, element1); + parcSortedList_Add(instance, element2); + parcSortedList_Add(instance, element3); + parcSortedList_Display(instance, 0); + + parcSortedList_Remove(instance, element2); + + assertTrue(parcSortedList_Size(instance) == 2, "Expected list to be 2 in size"); + + parcBuffer_Release(&element1); + parcBuffer_Release(&element2); + parcBuffer_Release(&element3); + parcBuffer_Release(&element4); + parcBuffer_Release(&element5); + parcBuffer_Release(&element6); + parcBuffer_Release(&element7); + parcBuffer_Release(&element8); + parcSortedList_Release(&instance); +} + +LONGBOW_TEST_CASE(Specialization, parcSortedList_GetAtIndex) +{ + PARCSortedList *instance = parcSortedList_Create(); + PARCBuffer *element1 = parcBuffer_WrapCString("1"); + PARCBuffer *element2 = parcBuffer_WrapCString("2"); + PARCBuffer *element3 = parcBuffer_WrapCString("3"); + PARCBuffer *element4 = parcBuffer_WrapCString("4"); + PARCBuffer *element7 = parcBuffer_WrapCString("7"); + PARCBuffer *element6 = parcBuffer_WrapCString("6"); + PARCBuffer *element5 = parcBuffer_WrapCString("5"); + PARCBuffer *element8 = parcBuffer_WrapCString("8"); + + parcSortedList_Add(instance, element1); + parcSortedList_Add(instance, element2); + parcSortedList_Add(instance, element3); + + PARCBuffer *actual = (PARCBuffer *) parcSortedList_GetAtIndex(instance, 1); + assertTrue(parcBuffer_Equals(element2, actual), "Got the wrong value at index 1"); + + parcBuffer_Release(&element1); + parcBuffer_Release(&element2); + parcBuffer_Release(&element3); + parcBuffer_Release(&element4); + parcBuffer_Release(&element5); + parcBuffer_Release(&element6); + parcBuffer_Release(&element7); + parcBuffer_Release(&element8); + parcSortedList_Release(&instance); +} + +LONGBOW_TEST_CASE(Specialization, parcSortedList_GetFirst) +{ + PARCSortedList *instance = parcSortedList_Create(); + PARCBuffer *element1 = parcBuffer_WrapCString("1"); + PARCBuffer *element2 = parcBuffer_WrapCString("2"); + PARCBuffer *element3 = parcBuffer_WrapCString("3"); + PARCBuffer *element4 = parcBuffer_WrapCString("4"); + PARCBuffer *element7 = parcBuffer_WrapCString("7"); + PARCBuffer *element6 = parcBuffer_WrapCString("6"); + PARCBuffer *element5 = parcBuffer_WrapCString("5"); + PARCBuffer *element8 = parcBuffer_WrapCString("8"); + + parcSortedList_Add(instance, element1); + parcSortedList_Add(instance, element2); + parcSortedList_Add(instance, element3); + + PARCBuffer *actual = (PARCBuffer *) parcSortedList_GetFirst(instance); + assertTrue(parcBuffer_Equals(element1, actual), "Got the wrong value."); + + parcBuffer_Release(&element1); + parcBuffer_Release(&element2); + parcBuffer_Release(&element3); + parcBuffer_Release(&element4); + parcBuffer_Release(&element5); + parcBuffer_Release(&element6); + parcBuffer_Release(&element7); + parcBuffer_Release(&element8); + parcSortedList_Release(&instance); +} + +LONGBOW_TEST_CASE(Specialization, parcSortedList_GetLast) +{ + PARCSortedList *instance = parcSortedList_Create(); + PARCBuffer *element1 = parcBuffer_WrapCString("1"); + PARCBuffer *element2 = parcBuffer_WrapCString("2"); + PARCBuffer *element3 = parcBuffer_WrapCString("3"); + PARCBuffer *element4 = parcBuffer_WrapCString("4"); + PARCBuffer *element7 = parcBuffer_WrapCString("7"); + PARCBuffer *element6 = parcBuffer_WrapCString("6"); + PARCBuffer *element5 = parcBuffer_WrapCString("5"); + PARCBuffer *element8 = parcBuffer_WrapCString("8"); + + parcSortedList_Add(instance, element1); + parcSortedList_Add(instance, element2); + parcSortedList_Add(instance, element3); + + PARCBuffer *actual = (PARCBuffer *) parcSortedList_GetLast(instance); + assertTrue(parcBuffer_Equals(element3, actual), "Got the wrong value at index 1"); + + parcBuffer_Release(&element1); + parcBuffer_Release(&element2); + parcBuffer_Release(&element3); + parcBuffer_Release(&element4); + parcBuffer_Release(&element5); + parcBuffer_Release(&element6); + parcBuffer_Release(&element7); + parcBuffer_Release(&element8); + parcSortedList_Release(&instance); +} + +LONGBOW_TEST_CASE(Specialization, parcSortedList_RemoveFirst) +{ + PARCSortedList *deque = parcSortedList_Create(); + + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCBuffer *object2 = parcBuffer_WrapCString("2"); + PARCBuffer *object3 = parcBuffer_WrapCString("3"); + + parcSortedList_Add(deque, object1); + parcSortedList_Add(deque, object2); + parcSortedList_Add(deque, object3); + + PARCBuffer *peek = parcSortedList_RemoveFirst(deque); + assertTrue(parcBuffer_Equals(object1, peek), "Objects out of order"); + + parcBuffer_Release(&peek); + parcBuffer_Release(&object1); + parcBuffer_Release(&object2); + parcBuffer_Release(&object3); + parcSortedList_Release(&deque); +} + +LONGBOW_TEST_CASE(Specialization, parcSortedList_RemoveFirst_SingleElement) +{ + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCSortedList *deque = parcSortedList_Create(); + parcSortedList_Add(deque, object1); + + PARCBuffer *peek = parcSortedList_RemoveFirst(deque); + assertTrue(parcBuffer_Equals(object1, peek), + "Objects out of order."); + + parcBuffer_Release(&peek); + parcBuffer_Release(&object1); + parcSortedList_Release(&deque); +} + +LONGBOW_TEST_CASE(Specialization, parcSortedList_RemoveLast) +{ + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + PARCBuffer *object2 = parcBuffer_WrapCString("2"); + PARCBuffer *object3 = parcBuffer_WrapCString("3"); + + PARCSortedList *deque = parcSortedList_Create(); + parcSortedList_Add(deque, object1); + parcSortedList_Add(deque, object2); + parcSortedList_Add(deque, object3); + + PARCBuffer *peek = parcSortedList_RemoveLast(deque); + assertTrue(parcBuffer_Equals(object3, peek), + "Objects out of order."); + + parcBuffer_Release(&peek); + + parcBuffer_Release(&object1); + parcBuffer_Release(&object2); + parcBuffer_Release(&object3); + parcSortedList_Release(&deque); +} + +LONGBOW_TEST_CASE(Specialization, parcSortedList_RemoveLast_SingleElement) +{ + PARCBuffer *object1 = parcBuffer_WrapCString("1"); + + PARCSortedList *deque = parcSortedList_Create(); + parcSortedList_Add(deque, object1); + + PARCBuffer *peek = parcSortedList_RemoveLast(deque); + assertTrue(parcBuffer_Equals(object1, peek), + "Objects out of order."); + + parcBuffer_Release(&object1); + parcSortedList_Release(&deque); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_SortedList); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_Stack.c b/libparc/parc/algol/test/test_parc_Stack.c new file mode 100755 index 00000000..3ca27682 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_Stack.c @@ -0,0 +1,119 @@ +/* + * 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. + */ + +/** + * @header <#Headline Name#> + * @abstract <#Abstract#> + * @discussion + * <#Discussion#> + * + */ +#include "../parc_Stack.c" + +#include <LongBow/unit-test.h> +#include <LongBow/debugging.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. + +#include <parc/algol/parc_ArrayList.h> +#include <parc/algol/parc_Deque.h> +#include <parc/algol/parc_SafeMemory.h> + +LONGBOW_TEST_RUNNER(test_parc_Stack) +{ + // 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_parc_Stack) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_Stack) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcStack_IsEmpty_PARCDeque); + LONGBOW_RUN_TEST_CASE(Global, parcStack_IsEmpty_PARCArrayList); +} + +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, parcStack_IsEmpty_PARCDeque) +{ + PARCStackInterface dequeAsStack = { + .parcStack_Release = (void (*)(void **))parcDeque_Release, + .parcStack_IsEmpty = (bool (*)(const void *))parcDeque_IsEmpty, + .parcStack_Peek = (void *(*)(const void *))parcDeque_PeekLast, + .parcStack_Pop = (void *(*)(void *))parcDeque_RemoveLast, + .parcStack_Push = (void *(*)(void *, void *))parcDeque_Append, + .parcStack_Search = NULL + }; + + PARCStack *stack = parcStack(parcDeque_Create(), &dequeAsStack); + + bool actual = parcStack_IsEmpty(stack); + parcStack_Release(&stack); + assertTrue(actual, "Expected the stack to be empty."); +} + +LONGBOW_TEST_CASE(Global, parcStack_IsEmpty_PARCArrayList) +{ + PARCStackInterface arrayListAsStack = { + .parcStack_Release = (void (*)(void **))parcArrayList_Destroy, + .parcStack_IsEmpty = (bool (*)(const void *))parcArrayList_IsEmpty, + .parcStack_Peek = (void *(*)(const void *))parcArrayList_Peek, + .parcStack_Pop = (void *(*)(void *))parcArrayList_Pop, + .parcStack_Push = (void *(*)(void *, void *))parcArrayList_Add, + .parcStack_Search = NULL + }; + + PARCStack *stack = parcStack(parcArrayList_Create(NULL), &arrayListAsStack); + + bool actual = parcStack_IsEmpty(stack); + parcStack_Release(&stack); + assertTrue(actual, "Expected the stack to be empty."); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_Stack); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_StdlibMemory.c b/libparc/parc/algol/test/test_parc_StdlibMemory.c new file mode 100644 index 00000000..7cf49991 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_StdlibMemory.c @@ -0,0 +1,326 @@ +/* + * 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 "../parc_StdlibMemory.c" + +#include <LongBow/testing.h> +#include <LongBow/debugging.h> + +#include <parc/testing/parc_MemoryTesting.h> + +LONGBOW_TEST_RUNNER(test_parc_StdlibMemory) +{ + // 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(Threads); + LONGBOW_RUN_TEST_FIXTURE(Performance); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(test_parc_StdlibMemory) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_StdlibMemory) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcStdlibMemory_Allocate); + LONGBOW_RUN_TEST_CASE(Global, parcStdlibMemory_MemAlign_BadAlignment); + LONGBOW_RUN_TEST_CASE(Global, parcStdlibMemory_MemAlign_BadSize); + LONGBOW_RUN_TEST_CASE(Global, parcStdlibMemory_AllocateAndClear); + LONGBOW_RUN_TEST_CASE(Global, parcStdlibMemory_AllocateAndClear_BadSize); + LONGBOW_RUN_TEST_CASE(Global, parcStdlibMemory_Reallocate); + LONGBOW_RUN_TEST_CASE(Global, parcStdlibMemory_Reallocate_NULL); + LONGBOW_RUN_TEST_CASE(Global, parcStdlibMemory_StringDuplicate); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaks allocations.", longBowTestCase_GetFullName(testCase))) { + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, parcStdlibMemory_Allocate) +{ + size_t size = 100; + + void *result = parcStdlibMemory_Allocate(size); + + assertNotNull(result, "parcStdlibMemory_Allocate failed: NULL result."); + assertTrue(parcStdlibMemory_Outstanding() == 1, + "Expected 1 outstanding allocation, actual %d", parcStdlibMemory_Outstanding()); + parcStdlibMemory_Deallocate(&result); +} + +LONGBOW_TEST_CASE(Global, parcStdlibMemory_MemAlign_BadAlignment) +{ + void *result; + size_t alignment = 3; + size_t size = 1200; + + int failure = parcStdlibMemory_MemAlign(&result, alignment, size); + assertTrue(failure == EINVAL, + "parcStdlibMemory_Allocate failed to report bad aligment specification"); + assertTrue(parcStdlibMemory_Outstanding() == 0, + "Expected 0 outstanding allocations, actual %d", parcStdlibMemory_Outstanding()); +} + +LONGBOW_TEST_CASE(Global, parcStdlibMemory_MemAlign_BadSize) +{ + void *result; + size_t alignment = sizeof(void *); + size_t size = 0; + + int failure = parcStdlibMemory_MemAlign(&result, alignment, size); + assertTrue(failure == EINVAL, + "parcStdlibMemory_Allocate failed to report bad aligment specification"); + assertTrue(parcStdlibMemory_Outstanding() == 0, + "Expected 0 outstanding allocation, actual %d", parcStdlibMemory_Outstanding()); +} + +LONGBOW_TEST_CASE(Global, parcStdlibMemory_AllocateAndClear) +{ + size_t size = 1200; + + void *result = parcStdlibMemory_AllocateAndClear(size); + assertNotNull(result, "parcStdlibMemory_Allocate failed: NULL result."); + + for (size_t i = 0; i < size; i++) { + assertTrue(((char *) result)[i] == 0, + "parcStdlibMemory_AllocateAndClear failed to zero memory at index %zd", i); + } + assertTrue(parcStdlibMemory_Outstanding() == 1, + "Expected 1 outstanding allocation, actual %d", parcStdlibMemory_Outstanding()); + parcStdlibMemory_Deallocate(&result); + assertTrue(parcStdlibMemory_Outstanding() == 0, + "Expected 0 outstanding allocation, actual %d", parcStdlibMemory_Outstanding()); +} + +LONGBOW_TEST_CASE(Global, parcStdlibMemory_AllocateAndClear_BadSize) +{ + void *result; + size_t alignment = sizeof(void *); + size_t size = 0; + + int failure = parcStdlibMemory_MemAlign(&result, alignment, size); + assertTrue(failure == EINVAL, + "parcStdlibMemory_Allocate failed to report bad aligment specification"); + assertTrue(parcStdlibMemory_Outstanding() == 0, + "Expected 0 outstanding allocations, actual %d", parcStdlibMemory_Outstanding()); +} + +static void +_test_SetMemory(unsigned char *memory, size_t size) +{ + for (size_t i = 0; i < size; i++) { + memory[i] = i; + } +} + +static void +_test_CheckMemory(unsigned char *memory, size_t size) +{ + for (size_t i = 0; i < size; i++) { + assertTrue(memory[i] == (i % 256), "memory failed to check at index %zd", i); + } +} + + +LONGBOW_TEST_CASE(Global, parcStdlibMemory_Reallocate) +{ + size_t size = 1200; + + void *result = parcStdlibMemory_AllocateAndClear(size); + assertNotNull(result, + "parcStdlibMemory_Allocate failed: NULL result."); + + _test_SetMemory(result, size); + _test_CheckMemory(result, size); + + result = parcStdlibMemory_Reallocate(result, size * 2); + + _test_CheckMemory(result, size); + + assertTrue(parcStdlibMemory_Outstanding() == 1, + "Expected 1 outstanding allocation, actual %d", parcStdlibMemory_Outstanding()); + parcStdlibMemory_Deallocate(&result); + assertTrue(parcStdlibMemory_Outstanding() == 0, + "Expected 0 outstanding allocations, actual %d", parcStdlibMemory_Outstanding()); +} + +LONGBOW_TEST_CASE(Global, parcStdlibMemory_Reallocate_NULL) +{ + void *result = NULL; + size_t size = 1200; + + result = parcStdlibMemory_Reallocate(result, size * 2); + _test_SetMemory(result, size * 2); + _test_CheckMemory(result, size * 2); + + assertTrue(parcStdlibMemory_Outstanding() == 1, + "Expected 1 outstanding allocation, actual %d", parcStdlibMemory_Outstanding()); + parcStdlibMemory_Deallocate(&result); + assertTrue(parcStdlibMemory_Outstanding() == 0, + "Expected 0 outstanding allocations, actual %d", parcStdlibMemory_Outstanding()); +} + +LONGBOW_TEST_CASE(Global, parcStdlibMemory_StringDuplicate) +{ + char *expected = "Hello World"; + char *actual = parcStdlibMemory_StringDuplicate(expected, strlen(expected)); + + assertTrue(expected != actual, + "Expected a distinct pointer unequal to the original string"); + assertTrue(strcmp(expected, actual) == 0, + "Expected strings to be equal. '%s' vs '%s'", expected, actual); + + assertTrue(parcStdlibMemory_Outstanding() == 1, + "Expected 1 outstanding allocation, actual %d", parcStdlibMemory_Outstanding()); + parcStdlibMemory_Deallocate((void **) &actual); + assertTrue(parcStdlibMemory_Outstanding() == 0, + "Expected 0 outstanding allocations, actual %d", parcStdlibMemory_Outstanding()); +} + +LONGBOW_TEST_FIXTURE(Threads) +{ + LONGBOW_RUN_TEST_CASE(Threads, Threads1000); +} + +LONGBOW_TEST_FIXTURE_SETUP(Threads) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Threads) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +void * +allocator(void *unused) +{ + for (int i = 0; i < 1000; i++) { + void *memory = parcStdlibMemory_Allocate(10); + parcStdlibMemory_Deallocate(&memory); + } + return 0; +} + +LONGBOW_TEST_CASE(Threads, Threads1000) +{ +#define NTHREADS 1000 + pthread_t thread[NTHREADS]; + + for (int i = 0; i < NTHREADS; i++) { + pthread_create(&thread[i], NULL, allocator, NULL); + } + for (int i = 0; i < NTHREADS; i++) { + pthread_join(thread[0], NULL); + } +} + +LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false) +{ + LONGBOW_RUN_TEST_CASE(Performance, parcStdlibMemory_AllocateDeallocate_Forward); + LONGBOW_RUN_TEST_CASE(Performance, parcStdlibMemory_AllocateDeallocate_Reverse); + LONGBOW_RUN_TEST_CASE(Performance, parcStdlibMemory_MemAlignDeallocate_Forward); + LONGBOW_RUN_TEST_CASE(Performance, parcStdlibMemory_MemAlignDeallocate_Reverse); +} + +LONGBOW_TEST_FIXTURE_SETUP(Performance) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Performance) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +#define ELEMENT_COUNT 1000000 +#define ELEMENT_SIZE 151 +void *memory[ELEMENT_COUNT]; + +LONGBOW_TEST_CASE(Performance, parcStdlibMemory_AllocateDeallocate_Forward) +{ + for (int i = 0; i < ELEMENT_COUNT; i++) { + memory[i] = parcStdlibMemory_Allocate(ELEMENT_SIZE); + } + for (int i = 0; i < ELEMENT_COUNT; i++) { + parcStdlibMemory_Deallocate(&memory[i]); + } +} + +LONGBOW_TEST_CASE(Performance, parcStdlibMemory_AllocateDeallocate_Reverse) +{ + for (int i = 0; i < ELEMENT_COUNT; i++) { + memory[i] = parcStdlibMemory_Allocate(ELEMENT_SIZE); + } + + int i = ELEMENT_COUNT; + do { + i--; + parcStdlibMemory_Deallocate(&memory[i]); + } while (i > 0); +} + +LONGBOW_TEST_CASE(Performance, parcStdlibMemory_MemAlignDeallocate_Forward) +{ + for (int i = 0; i < ELEMENT_COUNT; i++) { + parcStdlibMemory_MemAlign(&memory[i], sizeof(void *), ELEMENT_SIZE); + } + for (int i = 0; i < ELEMENT_COUNT; i++) { + parcStdlibMemory_Deallocate(&memory[i]); + } +} + +LONGBOW_TEST_CASE(Performance, parcStdlibMemory_MemAlignDeallocate_Reverse) +{ + for (int i = 0; i < ELEMENT_COUNT; i++) { + parcStdlibMemory_MemAlign(&memory[i], sizeof(void *), ELEMENT_SIZE); + } + + int i = ELEMENT_COUNT; + do { + i--; + parcStdlibMemory_Deallocate(&memory[i]); + } while (i > 0); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_StdlibMemory); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_String.c b/libparc/parc/algol/test/test_parc_String.c new file mode 100644 index 00000000..84d3d3da --- /dev/null +++ b/libparc/parc/algol/test/test_parc_String.c @@ -0,0 +1,210 @@ +/* + * 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 "../parc_String.c" + +#include <LongBow/testing.h> +#include <LongBow/debugging.h> +#include <parc/algol/parc_Memory.h> +#include <parc/algol/parc_SafeMemory.h> +#include <parc/algol/parc_DisplayIndented.h> + +#include <parc/testing/parc_MemoryTesting.h> +#include <parc/testing/parc_ObjectTesting.h> + +LONGBOW_TEST_RUNNER(parc_String) +{ + // 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(CreateAcquireRelease); + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_String) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_String) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(CreateAcquireRelease) +{ + LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease); +} + +LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease) +{ + if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) { + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease) +{ + PARCString *instance = parcString_Create("Hello World"); + assertNotNull(instance, "Expected non-null result from parcString_Create();"); + parcObjectTesting_AssertAcquireReleaseImpl(instance); + + parcString_Release(&instance); + assertNull(instance, "Expected null result from parcString_Release();"); +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcString_Compare); + LONGBOW_RUN_TEST_CASE(Global, parcString_Copy); + LONGBOW_RUN_TEST_CASE(Global, parcString_Display); + LONGBOW_RUN_TEST_CASE(Global, parcString_Equals); + LONGBOW_RUN_TEST_CASE(Global, parcString_HashCode); + LONGBOW_RUN_TEST_CASE(Global, parcString_IsValid); + LONGBOW_RUN_TEST_CASE(Global, parcString_ToJSON); + LONGBOW_RUN_TEST_CASE(Global, parcString_ToString); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) { + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, parcString_Compare) +{ + PARCString *string = parcString_Create("Hello1"); + PARCString *equivalent[2] = { + parcString_Create("Hello1"), + NULL + }; + PARCString *greater[2] = { + parcString_Create("Hello2"), + NULL + }; + PARCString *lesser[2] = { + parcString_Create("Hello0"), + NULL + }; + + parcObjectTesting_AssertCompareTo(parcString_Compare, string, equivalent, lesser, greater); + parcString_Release(&string); + parcString_Release(&equivalent[0]); + parcString_Release(&greater[0]); + parcString_Release(&lesser[0]); +} + +LONGBOW_TEST_CASE(Global, parcString_Copy) +{ + PARCString *instance = parcString_Create("Hello World"); + PARCString *copy = parcString_Copy(instance); + assertTrue(parcString_Equals(instance, copy), "Expected the copy to be equal to the original"); + + parcString_Release(&instance); + parcString_Release(©); +} + +LONGBOW_TEST_CASE(Global, parcString_Display) +{ + PARCString *instance = parcString_Create("Hello World"); + parcString_Display(instance, 0); + parcString_Release(&instance); +} + +LONGBOW_TEST_CASE(Global, parcString_Equals) +{ + PARCString *x = parcString_Create("Hello World"); + PARCString *y = parcString_Create("Hello World"); + PARCString *z = parcString_Create("Hello World"); + + parcObjectTesting_AssertEquals(x, y, z, NULL); + + parcString_Release(&x); + parcString_Release(&y); + parcString_Release(&z); +} + +LONGBOW_TEST_CASE(Global, parcString_HashCode) +{ + PARCString *x = parcString_Create("Hello World"); + PARCString *y = parcString_Create("Hello World"); + + parcObjectTesting_AssertHashCode(x, y); + + parcString_Release(&x); + parcString_Release(&y); +} + +LONGBOW_TEST_CASE(Global, parcString_IsValid) +{ + PARCString *instance = parcString_Create("Hello World"); + assertTrue(parcString_IsValid(instance), "Expected parcString_Create to result in a valid instance."); + + parcString_Release(&instance); + assertFalse(parcString_IsValid(instance), "Expected parcString_Release to result in an invalid instance."); +} + +LONGBOW_TEST_CASE(Global, parcString_ToJSON) +{ + PARCString *instance = parcString_Create("Hello World"); + + PARCJSON *json = parcString_ToJSON(instance); + + parcJSON_Release(&json); + + parcString_Release(&instance); +} + +LONGBOW_TEST_CASE(Global, parcString_ToString) +{ + PARCString *instance = parcString_Create("Hello World"); + + char *string = parcString_ToString(instance); + + assertNotNull(string, "Expected non-NULL result from parcString_ToString"); + + parcMemory_Deallocate((void **) &string); + parcString_Release(&instance); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_String); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} + + diff --git a/libparc/parc/algol/test/test_parc_Time.c b/libparc/parc/algol/test/test_parc_Time.c new file mode 100644 index 00000000..2befdde1 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_Time.c @@ -0,0 +1,144 @@ +/* + * 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 <LongBow/unit-test.h> +#include <LongBow/debugging.h> + +#include <parc/algol/parc_SafeMemory.h> +#include <parc/algol/parc_Memory.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../parc_Time.c" + +LONGBOW_TEST_RUNNER(test_parc_Time) +{ + // 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_parc_Time) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_Time) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcTime_TimevalAsString); + LONGBOW_RUN_TEST_CASE(Global, parcTime_TimevalAsISO8601); + LONGBOW_RUN_TEST_CASE(Global, parcTime_TimevalAsRFC3339); + LONGBOW_RUN_TEST_CASE(Global, parcTime_RFC3339_Now); + LONGBOW_RUN_TEST_CASE(Global, parcTime_NowTimeval); + LONGBOW_RUN_TEST_CASE(Global, parcTime_NowMicroseconds); +} + +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, parcTime_TimevalAsString) +{ + struct timeval timeval; + timeval.tv_sec = 0; + timeval.tv_usec = 1000; + + char *expected = "0.001000"; + char *actual = parcTime_TimevalAsString(timeval); + assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual); + parcMemory_Deallocate((void **) &actual); +} + +LONGBOW_TEST_CASE(Global, parcTime_TimevalAsISO8601) +{ + struct timeval timeval; + timeval.tv_sec = 0; + timeval.tv_usec = 1000; + + char *expected = "1970-01-01 00:00:00.001000Z"; + + char actual[64]; + parcTime_TimevalAsISO8601(&timeval, actual); + + assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual); +} + +LONGBOW_TEST_CASE(Global, parcTime_TimevalAsRFC3339) +{ + struct timeval timeval; + timeval.tv_sec = 0; + timeval.tv_usec = 1000; + + char *expected = "1970-01-01T00:00:00.001000Z"; + + char actual[64]; + parcTime_TimevalAsRFC3339(&timeval, actual); + + assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual); +} + +LONGBOW_TEST_CASE(Global, parcTime_RFC3339_Now) +{ + struct timeval timeval; + gettimeofday(&timeval, NULL); + + char actual[64]; + parcTime_TimevalAsRFC3339(&timeval, actual); + printf("%s\n", actual); +} + +LONGBOW_TEST_CASE(Global, parcTime_NowTimeval) +{ + struct timeval result = parcTime_NowTimeval(); + assertTrue(result.tv_sec != 0, "Expected NOW to not be zero."); +} + +LONGBOW_TEST_CASE(Global, parcTime_NowMicroseconds) +{ + uint64_t result = parcTime_NowMicroseconds(); + assertTrue(result != 0, "Expected NOW to not be zero."); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_Time); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_TreeMap.c b/libparc/parc/algol/test/test_parc_TreeMap.c new file mode 100755 index 00000000..9355380b --- /dev/null +++ b/libparc/parc/algol/test/test_parc_TreeMap.c @@ -0,0 +1,1565 @@ +/* + * 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 <unistd.h> +#include <fcntl.h> +#include <time.h> + +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +#include "../parc_TreeMap.c" + + +typedef struct { + int value; +} _Int; + +static _Int * +_int_Copy(const _Int *source); + +static bool +_int_Equals(const _Int *a, const _Int *b) +{ + return a->value == b->value; +} + +static int +_int_Compare(const _Int *a, const _Int *b) +{ + int result = 0; + if (a->value > b->value) { + result = 1; + } else if (a->value < b->value) { + result = -1; + } + + return result; +} + +parcObject_ExtendPARCObject(_Int, NULL, _int_Copy, NULL, _int_Equals, _int_Compare, NULL, NULL); + +static +parcObject_ImplementRelease(_int, _Int); + +static _Int * +_int_Create(const int value) +{ + _Int *newObj = parcObject_CreateInstance(_Int); + assertNotNull(newObj, "parcMemory_Allocate(%zu) returned NULL", sizeof(int)); + newObj->value = value; + return newObj; +} + +static _Int * +_int_Copy(const _Int *source) +{ + return _int_Create(source->value); +} + +static _Int * +_int_Set(_Int *obj, const int value) +{ + obj->value = value; + return obj; +} +static PARCBuffer* +strBuf(char *key) +{ + return parcBuffer_WrapCString(key); +} + + +LONGBOW_TEST_RUNNER(PARC_TreeMap) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); + LONGBOW_RUN_TEST_FIXTURE(Stress); +} + +LONGBOW_TEST_RUNNER_SETUP(PARC_TreeMap) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + + int seed = (int) time(NULL); + srandom(seed); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(PARC_TreeMap) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Create); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Acquire); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove_Ordered); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Put_Release); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Put_Ordered); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Put_OutOfOrder); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Put_Overwrite); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_ReleaseTillEmpty); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Size_Empty); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Size); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Size_Overwrite); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Get_EmptyTree); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Get_NonExistent); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Get_First); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Get); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Get_Last); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Get_Biggest); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Get_Smallest); + + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_FirstKey); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_FirstEntry); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_LastKey); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_LastEntry); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_FirstKey_Empty); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_LastKey_Empty); + + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_LowerEntry); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_LowerKey); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_HigherEntry); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_HigherKey); + + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove_First); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove_Last); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove_NonExistent); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_RemoveAndRelease_First); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_RemoveAndRelease); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_RemoveAndRelease_Last); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_RemoveAndRelease_NonExistent); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove_WithSuccessorNonRoot); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove_LeftChildRightChild); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Keys); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Values); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Equals_Empty); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Equals); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Equals_DifferentLength); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Equals_Not_Values); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Equals_Not_Keys); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Copy); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Copy_Direct); + + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Iterator); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_ValueIterator); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_KeyIterator); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove_Using_Iterator); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove_Element_Using_Iterator); +} + +#define N_TEST_ELEMENTS 42 + +typedef struct { + PARCTreeMap *testMap1; + PARCTreeMap *testMap2; + _Int *k[N_TEST_ELEMENTS]; + _Int *v[N_TEST_ELEMENTS]; +} TestData; + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + data->testMap1 = parcTreeMap_Create(); + data->testMap2 = parcTreeMap_CreateCustom((PARCTreeMap_CustomCompare *) _int_Compare); + + for (int i = 0; i < N_TEST_ELEMENTS; ++i) { + data->k[i] = _int_Create(i); + data->v[i] = _int_Create(i + 1000); + } + longBowTestCase_SetClipBoardData(testCase, data); + + return LONGBOW_STATUS_SUCCEEDED; +} + + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + parcTreeMap_Release(&data->testMap1); + parcTreeMap_Release(&data->testMap2); + + for (int i = 0; i < N_TEST_ELEMENTS; ++i) { + _int_Release(&(data->k[i])); + _int_Release(&(data->v[i])); + } + + parcMemory_Deallocate((void **) &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; +} + +static +int +recursiveCheckBlackDepth(const PARCTreeMap *tree, const _RBNode *node) +{ + assertNotNull(tree, "Null tree?\n"); + assertNotNull(node, "Null node?\n"); + if (node == tree->nil) { + return 0; + } + int right_depth = recursiveCheckBlackDepth(tree, node->rightChild); + int left_depth = recursiveCheckBlackDepth(tree, node->leftChild); + assertTrue(right_depth == left_depth, "Wrong depth!!\n"); + if (_rbNodeColor(node) == BLACK) { + return right_depth + 1; + } + return right_depth; +} + +static +void +rbCheckTree(const PARCTreeMap *tree) +{ + assertNotNull(tree, "Tree can't be NULL"); + _rbNodeAssertTreeInvariants(tree); + if (tree->size > 0) { + recursiveCheckBlackDepth(tree, tree->root); + } +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove_Ordered) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree1 = data->testMap1; + + for (int i = 0; i < 16; i++) { + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + } + + for (int i = 0; i < 14; i++) { + //rbPrintTreeString(tree1); + PARCObject *value = parcTreeMap_Remove(tree1, data->k[i]); + assertNotNull(value, "Data is null!"); + assertTrue(_int_Equals(value, data->v[i]), "Expect the ordered value."); + parcObject_Release(&value); + } +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Create) +{ + PARCTreeMap *map = parcTreeMap_Create(); + parcTreeMap_Release(&map); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Acquire) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *map = parcTreeMap_Acquire(data->testMap1); + parcTreeMap_Release(&map); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Put_Release) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree = data->testMap1; + + PARCBuffer *value1 = strBuf("value 1"); + PARCBuffer *key1 = strBuf("1"); + PARCBuffer *value2 = strBuf("value 2"); + PARCBuffer *key2 = strBuf("2"); + PARCBuffer *value3 = strBuf("value 3"); + PARCBuffer *key3 = strBuf("3"); + + parcTreeMap_Put(tree, key1, value1); + parcTreeMap_Put(tree, key2, value2); + parcTreeMap_Put(tree, key3, value3); + + parcBuffer_Release(&key1); + parcBuffer_Release(&value1); + parcBuffer_Release(&key2); + parcBuffer_Release(&value2); + parcBuffer_Release(&key3); + parcBuffer_Release(&value3); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Put_Overwrite) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree = data->testMap1; + + parcTreeMap_Put(tree, data->k[1], data->v[1]); + parcTreeMap_Put(tree, data->k[2], data->v[2]); + parcTreeMap_Put(tree, data->k[3], data->v[3]); + parcTreeMap_Put(tree, data->k[3], data->v[4]); + parcTreeMap_Put(tree, data->k[3], data->v[5]); + + assertTrue(3 == parcTreeMap_Size(tree), "Wrong size of tree should stay at 3"); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Put_Ordered) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree = data->testMap1; + + parcTreeMap_Put(tree, data->k[1], data->v[1]); + parcTreeMap_Put(tree, data->k[2], data->v[2]); + parcTreeMap_Put(tree, data->k[3], data->v[3]); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Put_OutOfOrder) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree1 = data->testMap1; + + parcTreeMap_Put(tree1, data->k[4], data->v[4]); + parcTreeMap_Put(tree1, data->k[2], data->v[2]); + parcTreeMap_Put(tree1, data->k[3], data->v[3]); + parcTreeMap_Put(tree1, data->k[1], data->v[1]); + + PARCTreeMap *tree2 = data->testMap2; + parcTreeMap_Put(tree2, data->k[1], data->v[1]); + parcTreeMap_Put(tree2, data->k[3], data->v[3]); + parcTreeMap_Put(tree2, data->k[2], data->v[2]); + parcTreeMap_Put(tree2, data->k[4], data->v[4]); + + assertTrue(parcTreeMap_Equals(tree1, tree2), "Expect trees to be Equal"); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Size_Empty) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree = data->testMap1; + + assertTrue(0 == parcTreeMap_Size(tree), "Wrong size of tree - empty, start"); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Size) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree = data->testMap1; + + parcTreeMap_Put(tree, data->k[4], data->v[4]); + parcTreeMap_Put(tree, data->k[2], data->v[2]); + parcTreeMap_Put(tree, data->k[3], data->v[3]); + + assertTrue(3 == parcTreeMap_Size(tree), "Wrong size of tree after add 3"); + + parcTreeMap_Put(tree, data->k[1], data->v[1]); + + assertTrue(4 == parcTreeMap_Size(tree), "Wrong size of tree after add 1 more"); + + parcTreeMap_RemoveAndRelease(tree, data->k[2]); + + size_t size = parcTreeMap_Size(tree); + + assertTrue(3 == size, "Wrong size of tree after 1 delete (%zu instead of 3)", size); + + parcTreeMap_Put(tree, data->k[7], data->v[7]); + + assertTrue(4 == parcTreeMap_Size(tree), "Wrong size of tree after add 1 more"); + + parcTreeMap_RemoveAndRelease(tree, data->k[3]); + assertTrue(3 == parcTreeMap_Size(tree), "Wrong size of tree after del 1 more - 3"); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_ReleaseTillEmpty) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree1 = data->testMap1; + PARCTreeMap *tree2 = data->testMap2; + + // This order of puts are removes exercises code paths + // in TreeMap not exercised in any other place. + int idx1a[7] = { 4, 2, 3, 1, 5, 7, 6 }; + int idx1b[7] = { 3, 1, 4, 2, 6, 5, 7 }; + int idx2a[7] = { 4, 6, 5, 7, 3, 1, 2 }; + int idx2b[7] = { 5, 7, 4, 6, 2, 3, 1 }; + + for (int i = 0; i < 7; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[idx1a[i]], data->v[idx1a[i]]); + parcTreeMap_Put(tree2, data->k[idx2a[i]], data->v[idx2a[i]]); + } + + for (int i = 0; i < 7; ++i) { + parcTreeMap_RemoveAndRelease(tree1, data->k[idx1b[i]]); + parcTreeMap_RemoveAndRelease(tree2, data->k[idx2b[i]]); + } + + size_t size; + size = parcTreeMap_Size(tree1); + + assertTrue(0 == size, "Wrong size of tree - empty (got %zu)", size); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Size_Overwrite) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree = data->testMap1; + + parcTreeMap_Put(tree, data->k[4], data->v[4]); + parcTreeMap_Put(tree, data->k[2], data->v[2]); + parcTreeMap_Put(tree, data->k[3], data->v[3]); + + // Size is 3 here, we'll insert the same number now.. + + parcTreeMap_Put(tree, data->k[3], data->v[23]); + + assertTrue(3 == parcTreeMap_Size(tree), "Wrong size of tree after overwrite"); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Get_EmptyTree) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree = data->testMap1; + + PARCObject *value = parcTreeMap_Get(tree, data->k[1]); + + assertTrue(NULL == value, "Object did not exist, must return NULL"); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Get_NonExistent) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree = data->testMap1; + + for (long i = 1; i < 10; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree, data->k[i], data->v[i]); + } + + PARCObject *value = parcTreeMap_Get(tree, data->k[23]); + + assertTrue(NULL == value, "Object did not exist, must return NULL"); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Get_First) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *tree = data->testMap1; + + for (long i = 1; i < 4; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree, data->k[i], data->v[i]); + } + + PARCObject *value = parcTreeMap_Get(tree, data->k[1]); + + assertTrue(_int_Equals(data->v[1], value), "Wrong value, got %ld", (long) value); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Get) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *tree = data->testMap1; + + for (long i = 1; i < 10; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree, data->k[i], data->v[i]); + } + + PARCObject *value = parcTreeMap_Get(tree, data->k[4]); + + assertTrue(_int_Equals(data->v[4], value), "Wrong value, got %ld", (long) value); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Get_Last) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *tree = data->testMap1; + + for (long i = 1; i < 10; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree, data->k[i], data->v[i]); + } + + PARCObject *value = parcTreeMap_Get(tree, data->k[9]); + + assertTrue(_int_Equals(data->v[9], value), "Wrong value, got %ld", (long) value); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Get_Smallest) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *tree = data->testMap1; + + for (long i = 30; i < 40; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree, data->k[i], data->v[i]); + } + for (long i = 1; i < 10; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree, data->k[i], data->v[i]); + } + for (long i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree, data->k[i], data->v[i]); + } + + + PARCObject *value = parcTreeMap_Get(tree, data->k[1]); + + assertTrue(_int_Equals(data->v[1], value), "Wrong value, got %ld", (long) value); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Get_Biggest) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *tree = data->testMap1; + + for (long i = 30; i < 40; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree, data->k[i], data->v[i]); + } + for (long i = 1; i < 10; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree, data->k[i], data->v[i]); + } + for (long i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree, data->k[i], data->v[i]); + } + + PARCObject *value = parcTreeMap_Get(tree, data->k[39]); + + assertTrue(_int_Equals(data->v[39], value), "Wrong value, got %ld", (long) value); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_FirstEntry) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *tree = data->testMap1; + + for (long i = 30; i < 40; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree, data->k[i], data->v[i]); + } + for (long i = 1; i < 10; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree, data->k[i], data->v[i]); + } + for (long i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree, data->k[i], data->v[i]); + } + + PARCKeyValue *entry = parcTreeMap_GetFirstEntry(tree); + + assertTrue(_int_Equals(data->k[1], parcKeyValue_GetKey(entry)), + "Wrong value, got %ld", (long) parcKeyValue_GetKey(entry)); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_FirstKey) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *tree = data->testMap1; + + for (long i = 30; i < 40; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree, data->k[i], data->v[i]); + } + for (long i = 1; i < 10; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree, data->k[i], data->v[i]); + } + for (long i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree, data->k[i], data->v[i]); + } + + PARCObject *key = parcTreeMap_GetFirstKey(tree); + + assertTrue(_int_Equals(data->k[1], key), "Wrong value, got %ld", (long) key); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_FirstKey_Empty) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *tree = data->testMap1; + + PARCObject *key = parcTreeMap_GetFirstKey(tree); + + assertNull(key, "Should get NULL on empty tree"); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_LastKey_Empty) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *tree = data->testMap1; + + PARCObject *key = parcTreeMap_GetLastKey(tree); + + assertNull(key, "Should get NULL on empty tree"); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_LastEntry) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *tree = data->testMap1; + + for (long i = 30; i < 40; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree, data->k[i], data->v[i]); + } + for (long i = 1; i < 10; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree, data->k[i], data->v[i]); + } + for (long i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree, data->k[i], data->v[i]); + } + + PARCKeyValue *entry = parcTreeMap_GetLastEntry(tree); + + assertTrue(_int_Equals(data->k[39], parcKeyValue_GetKey(entry)), + "Wrong value, got %ld", (long) parcKeyValue_GetKey(entry)); +} + + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_LastKey) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *tree = data->testMap1; + + for (long i = 30; i < 40; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree, data->k[i], data->v[i]); + } + for (long i = 1; i < 10; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree, data->k[i], data->v[i]); + } + for (long i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree, data->k[i], data->v[i]); + } + + PARCObject *key = parcTreeMap_GetLastKey(tree); + + assertTrue(_int_Equals(data->k[39], key), "Wrong value, got %ld", (long) key); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove_First) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree1 = data->testMap1; + PARCTreeMap *tree2 = data->testMap2; + + for (int i = 30; i < 40; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + + parcTreeMap_Put(tree1, data->k[1], data->v[1]); + + for (int i = 2; i < 10; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + + for (int i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + + PARCObject *value = parcTreeMap_Remove(tree1, data->k[1]); + parcObject_Release(&value); + + assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove"); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree1 = data->testMap1; + PARCTreeMap *tree2 = data->testMap2; + + for (int i = 31; i < 40; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + + parcTreeMap_Put(tree1, data->k[30], data->v[30]); + + for (int i = 2; i < 10; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + + for (int i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + + PARCObject *value = parcTreeMap_Remove(tree1, data->k[30]); + parcObject_Release(&value); + + assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove"); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove_Last) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree1 = data->testMap1; + PARCTreeMap *tree2 = data->testMap2; + + for (int i = 30; i < 40; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + + parcTreeMap_Put(tree1, data->k[41], data->v[41]); + + for (int i = 2; i < 10; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + for (int i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + + PARCObject *value = parcTreeMap_Remove(tree1, data->k[41]); + assertNotNull(value, "Expected to find some object."); + assertTrue(_int_Equals(data->v[41], value), "Expected value 41 in return"); + parcObject_Release(&value); + + assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees don't match after remove"); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_RemoveAndRelease_First) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree1 = data->testMap1; + PARCTreeMap *tree2 = data->testMap2; + + for (int i = 30; i < 40; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + + parcTreeMap_Put(tree1, data->k[1], data->v[1]); + + for (int i = 2; i < 10; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + for (int i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + + parcTreeMap_RemoveAndRelease(tree1, data->k[1]); + + assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove"); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_RemoveAndRelease) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree1 = data->testMap1; + PARCTreeMap *tree2 = data->testMap2; + + for (int i = 31; i < 40; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + + parcTreeMap_Put(tree1, data->k[30], data->v[30]); + + for (int i = 2; i < 10; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + for (int i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + + parcTreeMap_RemoveAndRelease(tree1, data->k[30]); + assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove"); + + for (int i = 20; i < 30; i++) { + parcTreeMap_RemoveAndRelease(tree1, data->k[i]); + parcTreeMap_RemoveAndRelease(tree2, data->k[49 - i]); + } + assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove"); + + for (int i = 2; i < 10; i++) { + parcTreeMap_RemoveAndRelease(tree1, data->k[i]); + parcTreeMap_RemoveAndRelease(tree2, data->k[11 - i]); + } + assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove"); + + for (int i = 31; i < 40; i++) { + parcTreeMap_RemoveAndRelease(tree1, data->k[i]); + parcTreeMap_RemoveAndRelease(tree2, data->k[70 - i]); + } + assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove"); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove_NonExistent) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree1 = data->testMap1; + PARCTreeMap *tree2 = data->testMap2; + + for (int i = 30; i < 40; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + for (int i = 2; i < 10; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + for (int i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + + PARCObject *element = parcTreeMap_Remove(tree1, data->k[0]); + + assertNull(element, "Return value must be NULL on non existing element"); + assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove"); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_RemoveAndRelease_NonExistent) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree1 = data->testMap1; + PARCTreeMap *tree2 = data->testMap2; + + for (int i = 30; i < 40; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + for (int i = 2; i < 10; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + for (int i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + + parcTreeMap_RemoveAndRelease(tree1, data->k[0]); + + assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove"); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove_WithSuccessorNonRoot) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *tree1 = data->testMap1; + PARCTreeMap *tree2 = data->testMap2; + + int idx1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 }; + int idx2[13] = { 8, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 }; + + for (int i = 0; i < 15; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[idx1[i]], data->v[idx1[i]]); + } + + for (int i = 0; i < 13; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree2, data->k[idx2[i]], data->v[idx2[i]]); + } + + _Int *key = _int_Create(4); + parcTreeMap_RemoveAndRelease(tree1, key); + parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 12)); + _int_Release(&key); + + assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove"); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove_LeftChildRightChild) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *tree1 = data->testMap1; + PARCTreeMap *tree2 = data->testMap2; + + int idx1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 }; + + for (int i = 0; i < 15; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[idx1[i]], data->v[idx1[i]]); + parcTreeMap_Put(tree2, data->k[idx1[i]], data->v[idx1[i]]); + } + + _Int *key = _int_Create(0); + parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 13)); + parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 7)); + parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 14)); + parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 6)); + parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 15)); + parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 12)); + parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 11)); + parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 10)); + parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 9)); + parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 8)); + parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 5)); + parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 4)); + parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 3)); + parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 2)); + parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 1)); + + parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 1)); + parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 2)); + parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 3)); + parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 4)); + parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 5)); + parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 6)); + parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 7)); + parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 8)); + parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 9)); + parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 10)); + parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 11)); + parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 12)); + parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 13)); + parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 14)); + parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 15)); + _int_Release(&key); + + assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove"); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_RemoveAndRelease_Last) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *tree1 = data->testMap1; + PARCTreeMap *tree2 = data->testMap2; + + for (int i = 30; i < 40; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + parcTreeMap_Put(tree1, data->k[41], data->v[41]); + for (int i = 2; i < 10; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + for (int i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + + parcTreeMap_RemoveAndRelease(tree1, data->k[41]); + + assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove"); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_LowerEntry) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *tree1 = data->testMap1; + + // Empty Tree + PARCKeyValue *kv = parcTreeMap_GetLowerEntry(tree1, data->k[23]); + assertNull(kv, "Expected a NULL return for LowerEntry() on empty tree"); + + // Fill Tree + int max = N_TEST_ELEMENTS - 1; + for (int i = 21; i <= max; ++i) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + } + for (int i = 1; i < 21; ++i) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + } + + // Using lowest key in tree + kv = parcTreeMap_GetLowerEntry(tree1, data->k[1]); + assertNull(kv, "Expected a NULL return for no lower entry"); + + // On all entries except the lowest tree + for (int i = max; i > 1; --i) { + kv = parcTreeMap_GetLowerEntry(tree1, data->k[i]); + assertNotNull(kv, "Expected a lower entry to exist"); + _Int *key = (_Int *) parcKeyValue_GetKey(kv); + assertTrue(_int_Equals(key, data->k[i - 1]), + "Expected entry with key %d, got %d", + data->k[i - 1]->value, key->value); + } +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_LowerKey) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *tree1 = data->testMap1; + + // Empty Tree + _Int *key = (_Int *) parcTreeMap_GetLowerKey(tree1, data->k[23]); + assertNull(key, "Expected a NULL return for LowerEntry() on empty tree"); + + int max = N_TEST_ELEMENTS - 1; + for (int i = 21; i <= max; ++i) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + } + for (int i = 1; i < 21; ++i) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + } + + // Using lowest key in tree + key = (_Int *) parcTreeMap_GetLowerKey(tree1, data->k[1]); + assertNull(key, "Expected a NULL return for no lower entry"); + + // On all entries except the lowest tree + for (int i = max; i > 1; --i) { + key = parcTreeMap_GetLowerKey(tree1, data->k[i]); + assertNotNull(key, "Expected a lower entry to exist"); + assertTrue(_int_Equals(key, data->k[i - 1]), + "Expected entry with key %d, got %d", + data->k[i - 1]->value, key->value); + } +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_HigherEntry) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *tree1 = data->testMap1; + + // Empty Tree + PARCKeyValue *kv = parcTreeMap_GetHigherEntry(tree1, data->k[23]); + assertNull(kv, "Expected a NULL return for HigherEntry() on empty tree"); + + int max = N_TEST_ELEMENTS - 2; + for (int i = 21; i <= max; ++i) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + } + for (int i = 1; i < 21; ++i) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + } + + // Using highest key in tree + kv = parcTreeMap_GetHigherEntry(tree1, data->k[max]); + assertNull(kv, "Expected a NULL return for no higher entry"); + + // On all entries except the lowest tree + for (int i = 1; i < max; ++i) { + kv = parcTreeMap_GetHigherEntry(tree1, data->k[i]); + assertNotNull(kv, "Expected a higher entry to exist"); + _Int *key = (_Int *) parcKeyValue_GetKey(kv); + assertTrue(_int_Equals(key, data->k[i + 1]), + "Expected entry with key %d, got %d", + data->k[i + 1]->value, key->value); + } +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_HigherKey) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *tree1 = data->testMap1; + + // Empty Tree + _Int *key = (_Int *) parcTreeMap_GetHigherKey(tree1, data->k[23]); + assertNull(key, "Expected a NULL return for LowerEntry() on empty tree"); + + int max = N_TEST_ELEMENTS - 2; + for (int i = 21; i <= max; ++i) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + } + for (int i = 1; i < 21; ++i) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + } + + key = (_Int *) parcTreeMap_GetHigherEntry(tree1, data->k[max]); + assertNull(key, "Expected a NULL return for no higher entry"); + + for (int i = 1; i < max; ++i) { + key = (_Int *) parcTreeMap_GetHigherKey(tree1, data->k[i]); + assertNotNull(key, "Expected a higher entry to exist"); + assertTrue(_int_Equals(key, data->k[i + 1]), + "Expected entry with key %d, got %d", + data->k[i + 1]->value, key->value); + } +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Keys) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree1 = data->testMap1; + + PARCList *list = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + + // Insert in tree out of order + for (int i = 10; i < 20; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + } + for (int i = 1; i < 10; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + } + + // Insert in list in order + for (int i = 1; i < 20; i++) { + // Add some elements to the tree + parcList_Add(list, data->k[i]); + } + + PARCList *keys = parcTreeMap_AcquireKeys(tree1); + + assertTrue(parcList_Equals(list, keys), "Key list doesnt' match"); + + parcList_Release(&keys); + parcList_Release(&list); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Values) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree1 = data->testMap1; + + PARCList *list = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); + + // Insert in tree out of order + for (int i = 10; i < 20; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + } + for (int i = 1; i < 10; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + } + + // Insert in list in order + for (int i = 1; i < 20; i++) { + // Add some elements to the tree + parcList_Add(list, data->v[i]); + } + + PARCList *values = parcTreeMap_AcquireValues(tree1); + + assertTrue(parcList_Equals(list, values), "Key list doesnt' match"); + + parcList_Release(&values); + parcList_Release(&list); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Equals_Empty) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree1 = data->testMap1; + PARCTreeMap *tree2 = data->testMap2; + + assertTrue(parcTreeMap_Equals(tree1, tree2), "Empty lists are not equal"); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Equals_DifferentLength) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree1 = data->testMap1; + PARCTreeMap *tree2 = data->testMap2; + + + for (int i = 1; i < 20; i++) { + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[i]); + } + + parcTreeMap_Put(tree2, data->k[41], data->v[41]); + + assertFalse(parcTreeMap_Equals(tree1, tree2), "Lists are equal"); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Equals_Not_Values) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree1 = data->testMap1; + PARCTreeMap *tree2 = data->testMap2; + + for (int i = 1; i < 20; i++) { + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i], data->v[20 - i]); + } + + assertFalse(parcTreeMap_Equals(tree1, tree2), "Lists are equal"); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Equals_Not_Keys) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree1 = data->testMap1; + PARCTreeMap *tree2 = data->testMap2; + + for (int i = 1; i < 20; i++) { + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[i + 1], data->v[i]); + } + assertTrue(parcTreeMap_Size(tree1) == parcTreeMap_Size(tree2), "Expect trees to have the same size."); + + assertFalse(parcTreeMap_Equals(tree1, tree2), "Lists should not be equal"); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Equals) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree1 = data->testMap1; + PARCTreeMap *tree2 = data->testMap2; + + for (int i = 1; i < 40; i++) { + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + parcTreeMap_Put(tree2, data->k[40 - i], data->v[40 - i]); + } + + assertTrue(parcTreeMap_Equals(tree1, tree2), "Lists are not equal"); +} + + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Copy) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCTreeMap *tree1 = data->testMap1; + PARCTreeMap *treeCopy = parcTreeMap_Copy(tree1); + + for (int i = 1; i < 10; i++) { + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + } + + assertFalse(parcTreeMap_Equals(tree1, treeCopy), "Lists are not equal"); + + parcTreeMap_Release(&treeCopy); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Copy_Direct) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *tree1 = data->testMap1; + + for (int i = 1; i < 20; i++) { + parcTreeMap_Put(tree1, data->k[i], data->v[i]); + } + + PARCTreeMap *treeCopy = parcTreeMap_Copy(tree1); + + assertTrue(parcTreeMap_Equals(tree1, treeCopy), "Lists are not equal"); + + parcTreeMap_Release(&treeCopy); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_ValueIterator) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *tree1 = data->testMap1; + + int idx1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 }; + + for (int i = 0; i < 15; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[idx1[i]], data->v[idx1[i]]); + } + + PARCIterator *it = parcTreeMap_CreateValueIterator(tree1); + + for (int idx = 1; parcIterator_HasNext(it); ++idx) { + _Int *value = (_Int *) parcIterator_Next(it); + assertTrue(_int_Equals(value, data->v[idx]), "Expected value %d got %d", data->v[idx]->value, value->value); + } + + parcIterator_Release(&it); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_KeyIterator) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *tree1 = data->testMap1; + + int idx1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 }; + + for (int i = 0; i < 15; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[idx1[i]], data->v[idx1[i]]); + } + + PARCIterator *it = parcTreeMap_CreateKeyIterator(tree1); + + for (int idx = 1; parcIterator_HasNext(it); ++idx) { + _Int *key = (_Int *) parcIterator_Next(it); + assertTrue(_int_Equals(key, data->k[idx]), + "Expected value %d got %d", + data->k[idx]->value, + key->value); + } + + parcIterator_Release(&it); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Iterator) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *tree1 = data->testMap1; + + int idx1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 }; + + for (int i = 0; i < 15; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[idx1[i]], data->v[idx1[i]]); + } + + PARCIterator *it = parcTreeMap_CreateKeyValueIterator(tree1); + + for (int idx = 1; parcIterator_HasNext(it); ++idx) { + PARCKeyValue *kv = (PARCKeyValue *) parcIterator_Next(it); + assertTrue(_int_Equals((_Int *) parcKeyValue_GetKey(kv), data->k[idx]), + "Expected value %d got %d", + data->k[idx]->value, + ((_Int *) parcKeyValue_GetKey(kv))->value); + } + + parcIterator_Release(&it); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove_Using_Iterator) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *tree1 = data->testMap1; + + int idx1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 }; + + for (int i = 0; i < 15; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[idx1[i]], data->v[idx1[i]]); + } + + PARCIterator *it = parcTreeMap_CreateKeyValueIterator(tree1); + for (int idx = 1; parcIterator_HasNext(it); ++idx) { + parcIterator_Next(it); + parcIterator_Remove(it); + } + parcIterator_Release(&it); + + assertTrue(parcTreeMap_Size(tree1) == 0, "Expect the tree to be empty after removes."); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove_Element_Using_Iterator) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCTreeMap *tree1 = data->testMap1; + PARCTreeMap *tree2 = data->testMap1; + + int idx1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 15, 13 }; //Missing 11 + + for (int i = 0; i < 14; i++) { + // Add some elements to the tree + parcTreeMap_Put(tree1, data->k[idx1[i]], data->v[idx1[i]]); + parcTreeMap_Put(tree2, data->k[idx1[i]], data->v[idx1[i]]); + } + + parcTreeMap_Put(tree1, data->k[11], data->v[11]); + + + PARCIterator *it = parcTreeMap_CreateKeyValueIterator(tree1); + for (int idx = 1; parcIterator_HasNext(it); ++idx) { + parcIterator_Next(it); + if (idx == 11) { + parcIterator_Remove(it); + } + } + parcIterator_Release(&it); + + assertTrue(parcTreeMap_Equals(tree1, tree2), "Expect the trees to be equal after remove."); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + //LONGBOW_RUN_TEST_CASE(Local, PARC_TreeMap_EnsureRemaining_NonEmpty); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Stress) +{ + // LongBow could use a command line option to enable/disable tests + // See LongBow issue #5 + if (getenv("LongBowStress")) { + LONGBOW_RUN_TEST_CASE(Stress, PARC_TreeMap_ExerciseRandomSeededSmall); + LONGBOW_RUN_TEST_CASE(Stress, PARC_TreeMap_ExerciseRandomSeeded); + } +} + +LONGBOW_TEST_FIXTURE_SETUP(Stress) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Stress) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Stress, PARC_TreeMap_ExerciseRandomSeededSmall) +{ + unsigned seed; + char *seedString; + + seedString = getenv("RBSeed"); + if (seedString) { + seed = (unsigned) atol(seedString); + } else { + seed = 4179329122; // known to fail + } + + for (int j = 0; j < 1; j++) { + // this test case should obtain a seed and number of iterations from a + // command line option once LongBow has that feature available + + srandom(seed); + PARCTreeMap *tree = parcTreeMap_Create(); + + int inserts = 0; + int deletes = 0; + + for (int i = 0; i < 100; i++) { + intptr_t item = 1 + (random() % 100); + int operation = random() % 1000; + if (operation < 400) { + inserts++; + parcTreeMap_Put(tree, (void *) item, (void *) (item << 8)); + } else { + deletes++; + parcTreeMap_Remove(tree, (void *) item); + } + rbCheckTree(tree); + } + + parcTreeMap_Release(&tree); + } +} + +LONGBOW_TEST_CASE(Stress, PARC_TreeMap_ExerciseRandomSeeded) +{ + PARCTreeMap *tree1; + unsigned seed; + char *seedString; + + // this test case should obtain a seed and number of iterations from a + // command line option once LongBow has that feature available + seedString = getenv("RBSeed"); + if (seedString) { + seed = (unsigned) atol(seedString); + } else { + seed = 4179329122; // known to fail + } + + srandom(seed); + + tree1 = parcTreeMap_Create(); + + int inserts = 0; + int deletes = 0; + + for (int i = 0; i < 100000; i++) { + intptr_t item = 1 + (random() % 10000); + int operation = random() % 1000; + if (operation < 400) { + inserts++; + parcTreeMap_Put(tree1, (void *) item, (void *) (item << 8)); + } else { + deletes++; + parcTreeMap_Remove(tree1, (void *) item); + } + rbCheckTree(tree1); + } + + parcTreeMap_Release(&tree1); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(PARC_TreeMap); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_TreeRedBlack.c b/libparc/parc/algol/test/test_parc_TreeRedBlack.c new file mode 100755 index 00000000..7fb1828a --- /dev/null +++ b/libparc/parc/algol/test/test_parc_TreeRedBlack.c @@ -0,0 +1,1461 @@ +/* + * 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 <unistd.h> +#include <fcntl.h> +#include <time.h> + +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +#include "../parc_TreeRedBlack.c" + + +void * +keyNewInt(int key) +{ + int *newKey = parcMemory_Allocate(sizeof(int)); + assertNotNull(newKey, "parcMemory_Allocate(%zu) returned NULL", sizeof(int)); + *newKey = key; + return newKey; +} + +void * +valueNewInt(int value) +{ + int *newValue = parcMemory_Allocate(sizeof(int)); + assertNotNull(newValue, "parcMemory_Allocate(%zu) returned NULL", sizeof(int)); + *newValue = value; + return newValue; +} + +void * +keyCopy(const void *key) +{ + return keyNewInt(*(int *) key); +} + +void * +valueCopy(const void *value) +{ + return valueNewInt(*(int *) value); +} + +void * +keyNew(char *key) +{ + return parcMemory_StringDuplicate(key, strlen(key)); +} + +void * +valueNew(char *value) +{ + return parcMemory_StringDuplicate(value, strlen(value)); +} + +int +intComp(const void *key1, const void *key2) +{ + if (*(int *) key1 < *(int *) key2) { + return -1; + } + if (*(int *) key1 == *(int *) key2) { + return 0; + } + return 1; +} + +bool +intEquals(const void *int1, const void *int2) +{ + return intComp(int1, int2) == 0; +} + +int +pointerComp(const void *key1, const void *key2) +{ + if (key1 < key2) { + return -1; + } + if (key1 == key2) { + return 0; + } + return 1; +} + +int +stringComp(const void *key1, const void *key2) +{ + // We assume all keys are strings. + return strcmp(key1, key2); +} + +void +keyFree(void **value) +{ + parcMemory_Deallocate((void **) value); + *value = NULL; +} + +void +valueFree(void **key) +{ + parcMemory_Deallocate((void **) key); + *key = NULL; +} + + +LONGBOW_TEST_RUNNER(PARC_TreeRedBlack) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); + LONGBOW_RUN_TEST_FIXTURE(Stress); +} + +LONGBOW_TEST_RUNNER_SETUP(PARC_TreeRedBlack) +{ + int seed = (int) time(NULL); + printf("Seed = %u\n", seed); + srandom(seed); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(PARC_TreeRedBlack) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Remove_Ordered); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Create); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Insert_Destroy); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Insert_Ordered); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Insert_OutOfOrder); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Insert_Overwrite); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_DestroyTillEmpty); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Size_Empty); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Size); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Size_Overwrite); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_EmptyTree); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_NonExistent); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_First); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_Last); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_Biggest); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_Smallest); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_FirstKey); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_LastKey); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_FirstKey_Empty); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_LastKey_Empty); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Remove_First); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Remove); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Remove_Last); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Remove_NonExistent); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_RemoveAndDestroy_First); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_RemoveAndDestroy); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_RemoveAndDestroy_Last); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_RemoveAndDestroy_NonExistent); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Remove_WithSuccessorNonRoot); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Remove_LeftChildRightChild); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Keys); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Values); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Empty); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Equals); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Func); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Equals_DifferentLength); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Not_Values); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Not_Values_Func); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Not_Keys); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Copy); + LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Copy_Direct); + //LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_ExerciseRandom); + //LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_ExerciseRootFailure); +} + +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; +} + +static +int +strComp(const void *s1, const void *s2) +{ + return strcmp((char *) s1, (char *) s2); +} + +static +bool +strEquals(const void *s1, const void *s2) +{ + return strcmp(s1, s2) == 0; +} + +static +int +recursiveCheckBlackDepth(const PARCTreeRedBlack *tree, const Node *node) +{ + assertNotNull(tree, "Null tree?\n"); + assertNotNull(node, "Null node?\n"); + if (node == tree->nil) { + return 0; + } + int right_depth = recursiveCheckBlackDepth(tree, node->right_child); + int left_depth = recursiveCheckBlackDepth(tree, node->left_child); + assertTrue(right_depth == left_depth, "Wrong depth!!\n"); + if (_rbNodeColor(node) == BLACK) { + return right_depth + 1; + } + return right_depth; +} + +static +void +rbCheckTree(const PARCTreeRedBlack *tree) +{ + assertNotNull(tree, "Tree can't be NULL"); + //printf("--- TREE ---\n"); + if (tree->size > 0) { + //_rbNodeRecursiveRun((PARCTreeRedBlack *)tree,tree->root,rbCheckNode,(void *)tree); + recursiveCheckBlackDepth(tree, tree->root); + } +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Remove_Ordered) +{ + char *insertList[16] = { + "01", + "02", + "03", + "04", + "05", + "06", + "07", + "08", + "09", + "10", + "11", + "12", + "13", + "14", + "15", + "16" + }; + + PARCTreeRedBlack *tree1; + + tree1 = parcTreeRedBlack_Create(strComp, NULL, NULL, strEquals, NULL, NULL); + + for (int i = 0; i < 16; i++) { + parcTreeRedBlack_Insert(tree1, insertList[i], insertList[i]); + } + + for (int i = 0; i < 14; i++) { + //rbPrintTreeString(tree1); + void *data = parcTreeRedBlack_Remove(tree1, insertList[i]); + assertNotNull(data, "Data is null!"); + } + + parcTreeRedBlack_Destroy(&tree1); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Create) +{ + PARCTreeRedBlack *tree; + + tree = parcTreeRedBlack_Create(stringComp, NULL, NULL, NULL, NULL, NULL); + + parcTreeRedBlack_Destroy(&tree); + + tree = parcTreeRedBlack_Create(stringComp, keyFree, NULL, NULL, valueFree, NULL); + + parcTreeRedBlack_Destroy(&tree); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Insert_Destroy) +{ + PARCTreeRedBlack *tree; + + tree = parcTreeRedBlack_Create(stringComp, keyFree, NULL, NULL, valueFree, NULL); + + void *value1 = valueNew("value 1"); + void *key1 = keyNew("1"); + void *value2 = valueNew("value 2"); + void *key2 = keyNew("2"); + void *value3 = valueNew("value 3"); + void *key3 = keyNew("3"); + + parcTreeRedBlack_Insert(tree, key1, value1); + parcTreeRedBlack_Insert(tree, key2, value2); + parcTreeRedBlack_Insert(tree, key3, value3); + + parcTreeRedBlack_Destroy(&tree); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Insert_Overwrite) +{ + PARCTreeRedBlack *tree; + + tree = parcTreeRedBlack_Create(stringComp, keyFree, NULL, NULL, valueFree, NULL); + + parcTreeRedBlack_Insert(tree, keyNew("1"), valueNew("v1")); + parcTreeRedBlack_Insert(tree, keyNew("2"), valueNew("v2")); + parcTreeRedBlack_Insert(tree, keyNew("3"), valueNew("v3")); + parcTreeRedBlack_Insert(tree, keyNew("3"), valueNew("v4")); + parcTreeRedBlack_Insert(tree, keyNew("3"), valueNew("v5")); + + assertTrue(3 == parcTreeRedBlack_Size(tree), "Wrong size of tree should stay at 3"); + + parcTreeRedBlack_Destroy(&tree); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Insert_Ordered) +{ + PARCTreeRedBlack *tree; + + tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + parcTreeRedBlack_Insert(tree, (void *) 1, (void *) 1001); + parcTreeRedBlack_Insert(tree, (void *) 2, (void *) 1002); + parcTreeRedBlack_Insert(tree, (void *) 3, (void *) 1003); + + parcTreeRedBlack_Destroy(&tree); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Insert_OutOfOrder) +{ + PARCTreeRedBlack *tree; + + tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + parcTreeRedBlack_Insert(tree, (void *) 4, (void *) 1004); + parcTreeRedBlack_Insert(tree, (void *) 2, (void *) 1002); + parcTreeRedBlack_Insert(tree, (void *) 3, (void *) 1003); + parcTreeRedBlack_Insert(tree, (void *) 1, (void *) 1001); + + parcTreeRedBlack_Destroy(&tree); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Size_Empty) +{ + PARCTreeRedBlack *tree; + + tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + assertTrue(0 == parcTreeRedBlack_Size(tree), "Wrong size of tree - empty, start"); + + parcTreeRedBlack_Destroy(&tree); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Size) +{ + PARCTreeRedBlack *tree; + size_t size; + + tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + parcTreeRedBlack_Insert(tree, (void *) 4, (void *) 1004); + parcTreeRedBlack_Insert(tree, (void *) 2, (void *) 1002); + parcTreeRedBlack_Insert(tree, (void *) 3, (void *) 1003); + + assertTrue(3 == parcTreeRedBlack_Size(tree), "Wrong size of tree after add 3"); + + parcTreeRedBlack_Insert(tree, (void *) 1, (void *) 1001); + + assertTrue(4 == parcTreeRedBlack_Size(tree), "Wrong size of tree after add 1 more"); + + parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 2); + + size = parcTreeRedBlack_Size(tree); + + assertTrue(3 == size, "Wrong size of tree after 1 delete (%zu instead of 3)", size); + + parcTreeRedBlack_Insert(tree, (void *) 7, (void *) 1007); + + assertTrue(4 == parcTreeRedBlack_Size(tree), "Wrong size of tree after add 1 more"); + + parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 3); + assertTrue(3 == parcTreeRedBlack_Size(tree), "Wrong size of tree after del 1 more - 3"); + + parcTreeRedBlack_Destroy(&tree); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_DestroyTillEmpty) +{ + PARCTreeRedBlack *tree; + size_t size; + + tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + parcTreeRedBlack_Insert(tree, (void *) 4, (void *) 1004); + parcTreeRedBlack_Insert(tree, (void *) 2, (void *) 1002); + parcTreeRedBlack_Insert(tree, (void *) 3, (void *) 1003); + parcTreeRedBlack_Insert(tree, (void *) 1, (void *) 1001); + parcTreeRedBlack_Insert(tree, (void *) 5, (void *) 1001); + parcTreeRedBlack_Insert(tree, (void *) 7, (void *) 1001); + parcTreeRedBlack_Insert(tree, (void *) 6, (void *) 1001); + + parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 3); + parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 1); + parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 4); + parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 2); + parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 6); + parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 5); + parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 7); + + size = parcTreeRedBlack_Size(tree); + + assertTrue(0 == size, "Wrong size of tree - empty (got %zu)", size); + + parcTreeRedBlack_Destroy(&tree); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Size_Overwrite) +{ + PARCTreeRedBlack *tree; + + tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + parcTreeRedBlack_Insert(tree, (void *) 4, (void *) 1004); + parcTreeRedBlack_Insert(tree, (void *) 2, (void *) 1002); + parcTreeRedBlack_Insert(tree, (void *) 3, (void *) 1003); + + // Size is 3 here, we'll insert the same number now.. + + parcTreeRedBlack_Insert(tree, (void *) 3, (void *) 1033); + + assertTrue(3 == parcTreeRedBlack_Size(tree), "Wrong size of tree after overwrite"); + + parcTreeRedBlack_Destroy(&tree); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_EmptyTree) +{ + PARCTreeRedBlack *tree; + + tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + void *value = parcTreeRedBlack_Get(tree, (void *) 1); + + assertTrue(NULL == value, "Object did not exist, must return NULL"); + + parcTreeRedBlack_Destroy(&tree); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_NonExistent) +{ + PARCTreeRedBlack *tree; + + tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + for (long i = 1; i < 10; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8)); + } + + void *value = parcTreeRedBlack_Get(tree, (void *) 100); + + assertTrue(NULL == value, "Object did not exist, must return NULL"); + + parcTreeRedBlack_Destroy(&tree); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_First) +{ + PARCTreeRedBlack *tree; + + tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + for (long i = 1; i < 4; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8)); + } + + void *value = parcTreeRedBlack_Get(tree, (void *) 1); + + assertTrue((1 << 8) == (long) value, "Wrong value, got %ld", (long) value); + + parcTreeRedBlack_Destroy(&tree); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get) +{ + PARCTreeRedBlack *tree; + + tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + for (long i = 1; i < 10; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8)); + } + + void *value = parcTreeRedBlack_Get(tree, (void *) 4); + + assertTrue((4 << 8) == (long) value, "Wrong value, got %ld", (long) value); + + parcTreeRedBlack_Destroy(&tree); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_Last) +{ + PARCTreeRedBlack *tree; + + tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + for (long i = 1; i < 10; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8)); + } + + void *value = parcTreeRedBlack_Get(tree, (void *) 9); + + assertTrue((9 << 8) == (long) value, "Wrong value, got %ld", (long) value); + + parcTreeRedBlack_Destroy(&tree); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_Smallest) +{ + PARCTreeRedBlack *tree; + + tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + for (long i = 30; i < 40; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8)); + } + for (long i = 1; i < 10; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8)); + } + for (long i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8)); + } + + + void *value = parcTreeRedBlack_Get(tree, (void *) 1); + + assertTrue((1 << 8) == (long) value, "Wrong value, got %ld", (long) value); + + parcTreeRedBlack_Destroy(&tree); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_Biggest) +{ + PARCTreeRedBlack *tree; + + tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + for (long i = 30; i < 40; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8)); + } + for (long i = 1; i < 10; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8)); + } + for (long i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8)); + } + + + void *value = parcTreeRedBlack_Get(tree, (void *) 39); + + assertTrue((39 << 8) == (long) value, "Wrong value, got %ld", (long) value); + + parcTreeRedBlack_Destroy(&tree); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_FirstKey) +{ + PARCTreeRedBlack *tree; + + tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + for (long i = 30; i < 40; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8)); + } + for (long i = 1; i < 10; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8)); + } + for (long i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8)); + } + + void *key = parcTreeRedBlack_FirstKey(tree); + + assertTrue(1 == (long) key, "Wrong value, got %ld", (long) key); + + parcTreeRedBlack_Destroy(&tree); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_FirstKey_Empty) +{ + PARCTreeRedBlack *tree; + + tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + void *key = parcTreeRedBlack_FirstKey(tree); + + assertNull(key, "Should get NULL on empty tree"); + + parcTreeRedBlack_Destroy(&tree); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_LastKey_Empty) +{ + PARCTreeRedBlack *tree; + + tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + void *key = parcTreeRedBlack_LastKey(tree); + + assertNull(key, "Should get NULL on empty tree"); + + parcTreeRedBlack_Destroy(&tree); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_LastKey) +{ + PARCTreeRedBlack *tree; + + tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + for (long i = 30; i < 40; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8)); + } + for (long i = 1; i < 10; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8)); + } + for (long i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8)); + } + + void *key = parcTreeRedBlack_LastKey(tree); + + assertTrue(39 == (long) key, "Wrong value, got %ld", (long) key); + + parcTreeRedBlack_Destroy(&tree); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Remove_First) +{ + PARCTreeRedBlack *tree1; + PARCTreeRedBlack *tree2; + + tree1 = parcTreeRedBlack_Create(intComp, keyFree, NULL, intEquals, valueFree, NULL); + tree2 = parcTreeRedBlack_Create(intComp, keyFree, NULL, intEquals, valueFree, NULL); + + for (int i = 30; i < 40; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8)); + parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8)); + } + + parcTreeRedBlack_Insert(tree1, keyNewInt(1), valueNewInt(1 << 8)); + + for (int i = 2; i < 10; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8)); + parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8)); + } + + for (int i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8)); + parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8)); + } + + int searchKey = 1; + + void *data = parcTreeRedBlack_Remove(tree1, &searchKey); + + valueFree(&data); + + assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove"); + + parcTreeRedBlack_Destroy(&tree1); + parcTreeRedBlack_Destroy(&tree2); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Remove) +{ + PARCTreeRedBlack *tree1; + PARCTreeRedBlack *tree2; + + tree1 = parcTreeRedBlack_Create(intComp, keyFree, NULL, intEquals, valueFree, NULL); + tree2 = parcTreeRedBlack_Create(intComp, keyFree, NULL, intEquals, valueFree, NULL); + + for (int i = 31; i < 40; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8)); + parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8)); + } + + parcTreeRedBlack_Insert(tree1, keyNewInt(30), valueNewInt(31 << 8)); + + for (int i = 2; i < 10; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8)); + parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8)); + } + + for (int i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8)); + parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8)); + } + + int searchKey = 30; + + void *data = parcTreeRedBlack_Remove(tree1, &searchKey); + + valueFree(&data); + + assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove"); + + parcTreeRedBlack_Destroy(&tree1); + parcTreeRedBlack_Destroy(&tree2); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Remove_Last) +{ + PARCTreeRedBlack *tree1; + PARCTreeRedBlack *tree2; + + tree1 = parcTreeRedBlack_Create(intComp, keyFree, NULL, intEquals, valueFree, NULL); + tree2 = parcTreeRedBlack_Create(intComp, keyFree, NULL, intEquals, valueFree, NULL); + + for (int i = 30; i < 40; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8)); + parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8)); + } + parcTreeRedBlack_Insert(tree1, keyNewInt(100), valueNewInt(100 << 8)); + for (int i = 2; i < 10; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8)); + parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8)); + } + for (int i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8)); + parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8)); + } + + int searchKey = 100; + + void *data = parcTreeRedBlack_Remove(tree1, &searchKey); + + valueFree(&data); + + assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove"); + + parcTreeRedBlack_Destroy(&tree1); + parcTreeRedBlack_Destroy(&tree2); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_RemoveAndDestroy_First) +{ + PARCTreeRedBlack *tree1; + PARCTreeRedBlack *tree2; + + tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + for (long i = 30; i < 40; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8)); + parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8)); + } + + parcTreeRedBlack_Insert(tree1, (void *) 1, (void *) (1 << 8)); + + for (long i = 2; i < 10; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8)); + parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8)); + } + for (long i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8)); + parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8)); + } + + parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 1); + + assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove"); + + parcTreeRedBlack_Destroy(&tree1); + parcTreeRedBlack_Destroy(&tree2); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_RemoveAndDestroy) +{ + PARCTreeRedBlack *tree1; + PARCTreeRedBlack *tree2; + + tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + for (long i = 31; i < 40; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8)); + parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8)); + } + + parcTreeRedBlack_Insert(tree1, (void *) 30, (void *) (30 << 8)); + + for (long i = 2; i < 10; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8)); + parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8)); + } + for (long i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8)); + parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8)); + } + + parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 30); + + assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove"); + + parcTreeRedBlack_Destroy(&tree1); + parcTreeRedBlack_Destroy(&tree2); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Remove_NonExistent) +{ + PARCTreeRedBlack *tree1; + PARCTreeRedBlack *tree2; + + tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + for (long i = 30; i < 40; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8)); + parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8)); + } + for (long i = 2; i < 10; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8)); + parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8)); + } + for (long i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8)); + parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8)); + } + + void *element = parcTreeRedBlack_Remove(tree1, (void *) 100); + + assertNull(element, "Return value must be NULL on non existing element"); + assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove"); + + parcTreeRedBlack_Destroy(&tree1); + parcTreeRedBlack_Destroy(&tree2); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_RemoveAndDestroy_NonExistent) +{ + PARCTreeRedBlack *tree1; + PARCTreeRedBlack *tree2; + + tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + for (long i = 30; i < 40; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8)); + parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8)); + } + for (long i = 2; i < 10; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8)); + parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8)); + } + for (long i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8)); + parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8)); + } + + parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 100); + + assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove"); + + parcTreeRedBlack_Destroy(&tree1); + parcTreeRedBlack_Destroy(&tree2); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Remove_WithSuccessorNonRoot) +{ + PARCTreeRedBlack *tree1; + PARCTreeRedBlack *tree2; + + long insert1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 }; + long insert2[13] = { 8, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 }; + + tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + + + for (int i = 0; i < 15; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, (void *) insert1[i], (void *) (insert1[i] << 8)); + } + + for (int i = 0; i < 13; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree2, (void *) insert2[i], (void *) (insert2[i] << 8)); + } + + parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 4); + parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 12); + + assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove"); + + parcTreeRedBlack_Destroy(&tree1); + parcTreeRedBlack_Destroy(&tree2); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Remove_LeftChildRightChild) +{ + PARCTreeRedBlack *tree1; + PARCTreeRedBlack *tree2; + + long insert1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 }; + long insert2[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 }; + + tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + + + for (int i = 0; i < 15; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, (void *) insert1[i], (void *) (insert1[i] << 8)); + } + + for (int i = 0; i < 15; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree2, (void *) insert2[i], (void *) (insert2[i] << 8)); + } + + parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 13); + parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 7); + parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 14); + parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 6); + parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 15); + parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 12); + parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 11); + parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 10); + parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 9); + parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 8); + parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 5); + parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 4); + parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 3); + parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 2); + parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 1); + + parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 1); + parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 2); + parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 3); + parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 4); + parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 5); + parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 6); + parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 7); + parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 8); + parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 9); + parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 10); + parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 11); + parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 12); + parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 13); + parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 14); + parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 15); + + //assertTrue(parcTreeRedBlack_Equals(tree1,tree2),"Trees dont match after remove"); + + parcTreeRedBlack_Destroy(&tree1); + parcTreeRedBlack_Destroy(&tree2); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_RemoveAndDestroy_Last) +{ + PARCTreeRedBlack *tree1; + PARCTreeRedBlack *tree2; + + tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + for (long i = 30; i < 40; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8)); + parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8)); + } + parcTreeRedBlack_Insert(tree1, (void *) 100, (void *) (100 << 8)); + for (long i = 2; i < 10; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8)); + parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8)); + } + for (long i = 20; i < 30; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8)); + parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8)); + } + + parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 100); + + assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove"); + + parcTreeRedBlack_Destroy(&tree1); + parcTreeRedBlack_Destroy(&tree2); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Keys) +{ + PARCTreeRedBlack *tree1; + PARCArrayList *list; + + tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + list = parcArrayList_Create(NULL); + + // Insert in tree out of order + for (long i = 10; i < 20; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8)); + } + for (long i = 1; i < 10; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8)); + } + + // Insert in list in order + for (long i = 1; i < 20; i++) { + // Add some elements to the tree + parcArrayList_Add(list, (void *) i); + } + + PARCArrayList *keys = parcTreeRedBlack_Keys(tree1); + + assertTrue(parcArrayList_Equals(list, keys), "Key list doesnt' match"); + + parcArrayList_Destroy(&keys); + parcArrayList_Destroy(&list); + parcTreeRedBlack_Destroy(&tree1); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Values) +{ + PARCTreeRedBlack *tree1; + PARCArrayList *list; + + tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + list = parcArrayList_Create(NULL); + + // Insert in tree out of order + for (long i = 10; i < 20; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8)); + } + for (long i = 1; i < 10; i++) { + // Add some elements to the tree + parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8)); + } + + // Insert in list in order + for (long i = 1; i < 20; i++) { + // Add some elements to the tree + parcArrayList_Add(list, (void *) (i << 8)); + } + + PARCArrayList *values = parcTreeRedBlack_Values(tree1); + + assertTrue(parcArrayList_Equals(list, values), "Key list doesnt' match"); + + parcArrayList_Destroy(&values); + parcArrayList_Destroy(&list); + parcTreeRedBlack_Destroy(&tree1); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Empty) +{ + PARCTreeRedBlack *tree1; + PARCTreeRedBlack *tree2; + + tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Empty lists are not equal"); + + parcTreeRedBlack_Destroy(&tree1); + parcTreeRedBlack_Destroy(&tree2); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Equals_DifferentLength) +{ + PARCTreeRedBlack *tree1; + PARCTreeRedBlack *tree2; + + int compareInserts = 100; + + tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + for (long i = 1; i < compareInserts; i++) { + parcTreeRedBlack_Insert(tree1, + (void *) i, + (void *) (i << 8)); + parcTreeRedBlack_Insert(tree2, + (void *) (compareInserts - i), + (void *) ((compareInserts - i) << 8)); + } + parcTreeRedBlack_Insert(tree2, (void *) (1000), (void *) ((12304) << 8)); + + assertFalse(parcTreeRedBlack_Equals(tree1, tree2), "Lists are equal"); + + parcTreeRedBlack_Destroy(&tree1); + parcTreeRedBlack_Destroy(&tree2); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Not_Values) +{ + PARCTreeRedBlack *tree1; + PARCTreeRedBlack *tree2; + + int compareInserts = 100; + + tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + for (long i = 1; i < compareInserts; i++) { + parcTreeRedBlack_Insert(tree1, + (void *) i, + (void *) (i << 8)); + parcTreeRedBlack_Insert(tree2, + (void *) (compareInserts - i), + (void *) ((compareInserts + i) << 8)); + } + + assertFalse(parcTreeRedBlack_Equals(tree1, tree2), "Lists are equal"); + + parcTreeRedBlack_Destroy(&tree1); + parcTreeRedBlack_Destroy(&tree2); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Not_Values_Func) +{ + PARCTreeRedBlack *tree1; + PARCTreeRedBlack *tree2; + + int compareInserts = 100; + + tree1 = parcTreeRedBlack_Create(pointerComp, keyFree, keyCopy, intEquals, valueFree, valueCopy); + tree2 = parcTreeRedBlack_Create(pointerComp, keyFree, keyCopy, intEquals, valueFree, valueCopy); + + for (int i = 1; i < compareInserts; i++) { + parcTreeRedBlack_Insert(tree1, + keyNewInt(i), + valueNewInt(i + 1000)); + parcTreeRedBlack_Insert(tree2, + keyNewInt(i), + valueNewInt(i + 2000)); + } + + assertFalse(parcTreeRedBlack_Equals(tree1, tree2), "Lists are equal"); + + parcTreeRedBlack_Destroy(&tree1); + parcTreeRedBlack_Destroy(&tree2); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Not_Keys) +{ + PARCTreeRedBlack *tree1; + PARCTreeRedBlack *tree2; + + int compareInserts = 100; + + tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + for (long i = 1; i < compareInserts; i++) { + parcTreeRedBlack_Insert(tree1, + (void *) i, + (void *) (i << 8)); + parcTreeRedBlack_Insert(tree2, + (void *) (compareInserts + i), + (void *) ((compareInserts - i) << 8)); + } + + assertFalse(parcTreeRedBlack_Equals(tree1, tree2), "Lists are equal"); + + parcTreeRedBlack_Destroy(&tree1); + parcTreeRedBlack_Destroy(&tree2); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Equals) +{ + PARCTreeRedBlack *tree1; + PARCTreeRedBlack *tree2; + + int compareInserts = 100; + + tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + for (long i = 1; i < compareInserts; i++) { + parcTreeRedBlack_Insert(tree1, + (void *) i, + (void *) (i << 8)); + parcTreeRedBlack_Insert(tree2, + (void *) (compareInserts - i), + (void *) ((compareInserts - i) << 8)); + } + + assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Lists are not equal"); + + parcTreeRedBlack_Destroy(&tree1); + parcTreeRedBlack_Destroy(&tree2); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Func) +{ + PARCTreeRedBlack *tree1; + PARCTreeRedBlack *tree2; + + int compareInserts = 100; + + tree1 = parcTreeRedBlack_Create(intComp, keyFree, keyCopy, intEquals, valueFree, valueCopy); + tree2 = parcTreeRedBlack_Create(intComp, keyFree, keyCopy, intEquals, valueFree, valueCopy); + + for (int i = 1; i < compareInserts; i++) { + parcTreeRedBlack_Insert(tree1, + keyNewInt(i), + valueNewInt(i + 1000)); + parcTreeRedBlack_Insert(tree2, + keyNewInt(i), + valueNewInt(i + 1000)); + } + + assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Lists are not equal"); + + parcTreeRedBlack_Destroy(&tree1); + parcTreeRedBlack_Destroy(&tree2); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Copy) +{ + PARCTreeRedBlack *tree1; + PARCTreeRedBlack *tree2; + + int compareInserts = 20; + + tree1 = parcTreeRedBlack_Create(intComp, keyFree, keyCopy, intEquals, valueFree, valueCopy); + + for (int i = 1; i < compareInserts; i++) { + void *key = keyNewInt(i); + void *value = valueNewInt(i + 1000); + //value = (void *) &((*(int*)value) + 100); + parcTreeRedBlack_Insert(tree1, key, value); + } + + tree2 = parcTreeRedBlack_Copy(tree1); + + assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Lists are not equal"); + + parcTreeRedBlack_Destroy(&tree1); + parcTreeRedBlack_Destroy(&tree2); +} + +LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Copy_Direct) +{ + PARCTreeRedBlack *tree1; + PARCTreeRedBlack *tree2; + + int compareInserts = 20; + + tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + for (long i = 1; i < compareInserts; i++) { + parcTreeRedBlack_Insert(tree1, + (void *) i, + (void *) (i << 8)); + } + + tree2 = parcTreeRedBlack_Copy(tree1); + + assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Lists are not equal"); + + parcTreeRedBlack_Destroy(&tree1); + parcTreeRedBlack_Destroy(&tree2); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + //LONGBOW_RUN_TEST_CASE(Local, PARC_TreeRedBlack_EnsureRemaining_NonEmpty); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Stress) +{ + // LongBow could use a command line option to enable/disable tests + // See LongBow issue #5 + if (getenv("LongBowStress")) { + LONGBOW_RUN_TEST_CASE(Stress, PARC_TreeRedBlack_ExerciseRandomSeededSmall); + LONGBOW_RUN_TEST_CASE(Stress, PARC_TreeRedBlack_ExerciseRandomSeeded); + } +} + +LONGBOW_TEST_FIXTURE_SETUP(Stress) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Stress) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Stress, PARC_TreeRedBlack_ExerciseRandomSeededSmall) +{ + PARCTreeRedBlack *tree1; + unsigned seed; + char *seedString; + + seedString = getenv("RBSeed"); + if (seedString) { + seed = (unsigned) atol(seedString); + } else { + seed = 4179329122; // known to fail + } + + for (int j = 0; j < 1; j++) { + // this test case should obtain a seed and number of iterations from a + // command line option once LongBow has that feature available + + printf("Random seed %u\n", seed); + + srandom(seed); + tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + int inserts = 0; + int deletes = 0; + + for (int i = 0; i < 100; i++) { + intptr_t item = 1 + (random() % 100); + int operation = random() % 1000; + if (operation < 400) { + inserts++; + parcTreeRedBlack_Insert(tree1, (void *) item, (void *) (item << 8)); + } else { + deletes++; + parcTreeRedBlack_Remove(tree1, (void *) item); + } + rbCheckTree(tree1); + } + + parcTreeRedBlack_Destroy(&tree1); + } +} + +LONGBOW_TEST_CASE(Stress, PARC_TreeRedBlack_ExerciseRandomSeeded) +{ + PARCTreeRedBlack *tree1; + unsigned seed; + char *seedString; + + // this test case should obtain a seed and number of iterations from a + // command line option once LongBow has that feature available + seedString = getenv("RBSeed"); + if (seedString) { + seed = (unsigned) atol(seedString); + } else { + seed = 4179329122; // known to fail + } + printf("Random seed %u\n", seed); + + srandom(seed); + + tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL); + + int inserts = 0; + int deletes = 0; + + for (int i = 0; i < 100000; i++) { + intptr_t item = 1 + (random() % 10000); + int operation = random() % 1000; + if (operation < 400) { + inserts++; + parcTreeRedBlack_Insert(tree1, (void *) item, (void *) (item << 8)); + } else { + deletes++; + parcTreeRedBlack_Remove(tree1, (void *) item); + } + rbCheckTree(tree1); + } + + parcTreeRedBlack_Destroy(&tree1); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(PARC_TreeRedBlack); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_URI.c b/libparc/parc/algol/test/test_parc_URI.c new file mode 100644 index 00000000..5050deb3 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_URI.c @@ -0,0 +1,642 @@ +/* + * 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 "../parc_URI.c" +#include <LongBow/unit-test.h> + +#include <stdint.h> + +#include <parc/algol/parc_Hash.h> +#include <parc/algol/parc_SafeMemory.h> +#include <parc/testing/parc_ObjectTesting.h> + +#include <parc/algol/parc_Hash.h> + +#include "_test_parc_URI.h" + +LONGBOW_TEST_RUNNER(parcURI) +{ + LONGBOW_RUN_TEST_FIXTURE(parcURI); +} + +LONGBOW_TEST_RUNNER_SETUP(parcURI) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(parcURI) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("Tests leak memory by %d allocations\n", outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(parcURI) +{ + LONGBOW_RUN_TEST_CASE(parcURI, parseScheme); + LONGBOW_RUN_TEST_CASE(parcURI, parseScheme_Only); + LONGBOW_RUN_TEST_CASE(parcURI, parseScheme_BadScheme); + LONGBOW_RUN_TEST_CASE(parcURI, parseScheme_EmptyScheme); + + LONGBOW_RUN_TEST_CASE(parcURI, parseAuthority); + LONGBOW_RUN_TEST_CASE(parcURI, parseAuthority_NoAuthority); + LONGBOW_RUN_TEST_CASE(parcURI, parseAuthority_NoPath); + + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_Acquire); + + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_AuthorityEquals_SamePointer); + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_AuthorityEquals_NullPointers); + + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_QueryEquals_SamePointer); + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_QueryEquals_NullPointers); + + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_FragmentEquals_SamePointer); + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_FragmentEquals_NullPointers); + + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SchemeEquals_SamePointer); + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SchemeEquals_NullPointers); + + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_Parse); + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_Parse_NoScheme); + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_Parse_SchemeOnly); + + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetScheme); + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetScheme_Reset); + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetScheme_Resetting); + + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetFragment); + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetFragment_Reset); + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetFragment_Resetting); + + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetQuery); + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetQuery_Reset); + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetQuery_Resetting); + + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetAuthority); + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetAuthority_Reset); + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetAuthority_Resetting); + + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_Equals_Contract); + + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_GetPath); + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_GetQuery); + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_GetFragment); + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_Copy); + LONGBOW_RUN_TEST_CASE(parcURI, parcURI_ToString_Full); + + LONGBOW_RUN_TEST_CASE(parcURI, PARCURI_ToString_SchemeOnly); + LONGBOW_RUN_TEST_CASE(parcURI, PARCURI_ToString_NoAuthority); +} + +LONGBOW_TEST_FIXTURE_SETUP(parcURI) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(parcURI) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(parcURI, parcURI_Acquire) +{ + char *uriString = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT; + + uriString = parcMemory_StringDuplicate(uriString, strlen(uriString)); + + PARCURI *uri = parcURI_Parse(uriString); + + PARCURI *handle = parcURI_Acquire(uri); + + assertTrue(parcURI_Equals(uri, handle), "Expected URI and acquired handle to be equal"); + + parcURI_Release(&handle); + parcURI_Release(&uri); + parcMemory_Deallocate((void **) &uriString); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_AuthorityEquals_SamePointer) +{ + char *authority = "authority@auth"; + assertTrue(_parcURI_AuthorityEquals(authority, authority), + "Expected authorities to be equal since they're the same pointers: %p - %p", + (void *) authority, (void *) authority); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_AuthorityEquals_NullPointers) +{ + char *authority = "authority@auth"; + assertFalse(_parcURI_AuthorityEquals(NULL, authority), "Expected authorities to not be equal since one is NULL"); + assertFalse(_parcURI_AuthorityEquals(authority, NULL), "Expected authorities to not be equal since one is NULL"); + assertTrue(_parcURI_AuthorityEquals(NULL, NULL), "Expected authorities to be equal since both are NULL"); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_QueryEquals_SamePointer) +{ + char *query = "query"; + assertTrue(_parcURI_QueryEquals(query, query), + "Expected queries to be equal since they're the same pointers: %p - %p", + (void *) query, (void *) query); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_QueryEquals_NullPointers) +{ + char *query = "query"; + assertFalse(_parcURI_QueryEquals(NULL, query), "Expected queries to not be equal since one is NULL"); + assertFalse(_parcURI_QueryEquals(query, NULL), "Expected queries to not be equal since one is NULL"); + assertTrue(_parcURI_QueryEquals(NULL, NULL), "Expected queries to be equal since both are NULL"); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_FragmentEquals_SamePointer) +{ + char *fragment = "fragment"; + assertTrue(_parcURI_FragmentEquals(fragment, fragment), + "Expected fragments to be equal since they're the same pointers: %p - %p", + (void *) fragment, (void *) fragment); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_FragmentEquals_NullPointers) +{ + char *fragment = "fragment"; + assertFalse(_parcURI_FragmentEquals(NULL, fragment), "Expected fragments to not be equal since one is NULL"); + assertFalse(_parcURI_FragmentEquals(fragment, NULL), "Expected fragments to not be equal since one is NULL"); + assertTrue(_parcURI_FragmentEquals(NULL, NULL), "Expected fragments to be equal since both are NULL"); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_SchemeEquals_SamePointer) +{ + char *scheme = "scheme"; + assertTrue(_parcURI_SchemeEquals(scheme, scheme), + "Expected schemes to be equal since they're the same pointers: %p - %p", + (void *) scheme, (void *) scheme); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_SchemeEquals_NullPointers) +{ + char *scheme = "scheme"; + assertFalse(_parcURI_SchemeEquals(NULL, scheme), "Expected schemes to not be equal since one is NULL"); + assertFalse(_parcURI_SchemeEquals(scheme, NULL), "Expected schemes to not be equal since one is NULL"); + assertTrue(_parcURI_SchemeEquals(NULL, NULL), "Expected schemes to be equal since both are NULL"); +} + +LONGBOW_TEST_CASE(parcURI, parseScheme_EmptyScheme) +{ + const char *pointer; + char *actual = _parseScheme(":", &pointer); // empty string + assertNull(actual, "Parsed scheme should be NULL since the input string was empty."); + actual = _parseScheme("", &pointer); // empty string + assertNull(actual, "Parsed scheme should be NULL since the input string was empty."); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_Parse) +{ + char *uriString = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT; + + uriString = parcMemory_StringDuplicate(uriString, strlen(uriString)); + + PARCURI *uri = parcURI_Parse(uriString); + assertNotNull(uri, "Expected non-null result for '%s'", uriString); + + memset(uriString, 0, strlen(uriString)); + + assertTrue(strcmp(URI_SCHEME, parcURI_GetScheme(uri)) == 0, + "Expected '%s', actual '%s'", URI_SCHEME, parcURI_GetScheme(uri)); + assertTrue(strcmp(URI_AUTHORITY, parcURI_GetAuthority(uri)) == 0, + "Expected '%s', actual '%s'", URI_AUTHORITY, parcURI_GetAuthority(uri)); + assertTrue(strcmp(URI_QUERY, parcURI_GetQuery(uri)) == 0, + "Expected '%s', actual '%s'", URI_QUERY, parcURI_GetQuery(uri)); + assertTrue(strcmp(URI_FRAGMENT, parcURI_GetFragment(uri)) == 0, + "Expected '%s', actual '%s'", URI_FRAGMENT, parcURI_GetFragment(uri)); + + parcMemory_Deallocate((void **) &uriString); + + parcURI_Release(&uri); + assertNull(uri, "Expected parcURI_Release to null the pointer."); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_Parse_NoScheme) +{ + char *uriString = "/" URI_PATH_SEGMENT; + + uriString = parcMemory_StringDuplicate(uriString, strlen(uriString)); + + PARCURI *uri = parcURI_Parse(uriString); + assertNull(uri, + "Expected null result for '%s'", uriString); + parcMemory_Deallocate((void **) &uriString); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_Parse_SchemeOnly) +{ + char *uriString = URI_SCHEME ":"; + + uriString = parcMemory_StringDuplicate(uriString, strlen(uriString)); + + PARCURI *uri = parcURI_Parse(uriString); + assertNotNull(uri, + "Expected non-null result for '%s'", uriString); + + memset(uriString, 0, strlen(uriString)); + + assertTrue(strcmp(URI_SCHEME, parcURI_GetScheme(uri)) == 0, + "Expected '%s', actual '%s'", URI_SCHEME, parcURI_GetScheme(uri)); + assertNull(parcURI_GetAuthority(uri), + "Expected NULL, actual '%s'", parcURI_GetAuthority(uri)); + assertNull(parcURI_GetQuery(uri), + "Expected NULL, actual '%s'", parcURI_GetQuery(uri)); + assertNull(parcURI_GetFragment(uri), + "Expected NULL, actual '%s'", parcURI_GetFragment(uri)); + + parcMemory_Deallocate((void **) &uriString); + parcURI_Release(&uri); + assertNull(uri, + "Expected parcURI_Release to null the pointer."); +} + +LONGBOW_TEST_CASE(parcURI, parseScheme) +{ + const char *pointer; + char *actual = _parseScheme(URI_FULL, &pointer); + assertTrue(strcmp(URI_SCHEME, actual) == 0, + "Expected '%s' actual '%s'", URI_SCHEME, actual); + parcMemory_Deallocate((void **) &actual); +} + +LONGBOW_TEST_CASE(parcURI, parseScheme_Only) +{ + const char *pointer; + char *actual = _parseScheme(URI_SCHEME ":", &pointer); + assertTrue(strcmp(URI_SCHEME, actual) == 0, + "Expected '%s' actual '%s'", URI_SCHEME, actual); + parcMemory_Deallocate((void **) &actual); +} + +LONGBOW_TEST_CASE(parcURI, parseScheme_BadScheme) +{ + const char *pointer; + char *actual = _parseScheme("", &pointer); + assertNull(actual, + "Expected NULL actual '%s'", actual); +} + +LONGBOW_TEST_CASE(parcURI, PARCURI_GetAuthority) +{ + PARCURI *uri = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT); + const char *actual = parcURI_GetAuthority(uri); + assertTrue(strcmp(TEST_URI_AUTHORITY, actual) == 0, + "Expected '%s' actual '%s'", URI_AUTHORITY, actual); + parcURI_Release(&uri); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_GetQuery) +{ + PARCURI *uri = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT); + const char *actual = parcURI_GetQuery(uri); + assertTrue(strcmp(URI_QUERY, actual) == 0, + "Expected '%s' actual '%s'", URI_FRAGMENT, actual); + + parcURI_Release(&uri); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_GetFragment) +{ + PARCURI *uri = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT); + const char *actual = parcURI_GetFragment(uri); + assertTrue(strcmp(URI_FRAGMENT, actual) == 0, + "Expected '%s' actual '%s'", URI_FRAGMENT, actual); + parcURI_Release(&uri); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_GetPath) +{ + char *uriString = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT; + PARCURI *uri = parcURI_Parse(uriString); + PARCURIPath *actual = parcURI_GetPath(uri); + + char *string = parcURIPath_ToString(actual); + + char *expected = URI_PATH_SEGMENT "/" URI_PATH_SEGMENT; + assertTrue(strcmp(expected, string) == 0, "Expected '%s' actual '%s'", expected, string); + + parcMemory_Deallocate((void **) &string); + parcURI_Release(&uri); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_Copy) +{ + PARCURI *uri = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT); + PARCURI *uri2 = parcURI_Copy(uri); + + char *expected = parcURI_ToString(uri); + char *actual = parcURI_ToString(uri2); + + assertTrue(strcmp(expected, actual) == 0, + "Expected '%s' actual '%s'", expected, actual); + parcMemory_Deallocate((void **) &expected); + parcMemory_Deallocate((void **) &actual); + parcURI_Release(&uri); + parcURI_Release(&uri2); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_Equals_Contract) +{ + PARCURI *x = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT); + PARCURI *y = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT); + PARCURI *z = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT); + PARCURI *u = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "?" URI_QUERY); + + parcObjectTesting_AssertEqualsFunction(parcURI_Equals, x, y, z, u); + + parcURI_Release(&x); + parcURI_Release(&y); + parcURI_Release(&z); + parcURI_Release(&u); +} + +LONGBOW_TEST_CASE(parcURI, PARCURI_GetScheme) +{ + PARCURI *uri = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT); + const char *actual = parcURI_GetScheme(uri); + assertTrue(strcmp(TEST_URI_SCHEME, actual) == 0, + "Expected '%s' actual '%s'", TEST_URI_SCHEME, actual); + parcURI_Release(&uri); +} + +LONGBOW_TEST_CASE(parcURI, PARCURI_Parse) +{ + PARCURI *uri = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT); + assertNotNull(uri, + "Expected a non-null result."); + + assertTrue(strcmp(URI_SCHEME, parcURI_GetScheme(uri)) == 0, + "Expected '%s', actual '%s'", URI_SCHEME, parcURI_GetScheme(uri)); + assertTrue(strcmp(URI_AUTHORITY, parcURI_GetAuthority(uri)) == 0, + "Expected '%s', actual '%s'", URI_AUTHORITY, parcURI_GetAuthority(uri)); + assertTrue(strcmp(URI_QUERY, parcURI_GetQuery(uri)) == 0, + "Expected '%s', actual '%s'", URI_QUERY, parcURI_GetQuery(uri)); + assertTrue(strcmp(URI_FRAGMENT, parcURI_GetFragment(uri)) == 0, + "Expected '%s', actual '%s'", URI_FRAGMENT, parcURI_GetFragment(uri)); + + parcURI_Release(&uri); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_ToString_Full) +{ + char *expected = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT; + + PARCURI *uri = parcURI_Parse(expected); + char *actual = parcURI_ToString(uri); + + assertTrue(strcmp(expected, actual) == 0, + "Expected '%s' actual '%s'", expected, actual); + parcMemory_Deallocate((void **) &actual); + parcURI_Release(&uri); +} + +LONGBOW_TEST_CASE(parcURI, PARCURI_ToString_SchemeOnly) +{ + char *expected = URI_SCHEME ":" "/"; + PARCURI *uri = parcURI_Parse(expected); + char *actual = parcURI_ToString(uri); + + assertTrue(strcmp(expected, actual) == 0, + "Expected '%s' actual '%s'", expected, actual); + parcURI_Release(&uri); + parcMemory_Deallocate((void **) &actual); +} + +LONGBOW_TEST_CASE(parcURI, PARCURI_ToString_NoAuthority) +{ + char *expected = URI_SCHEME ":" "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT; + PARCURI *uri = parcURI_Parse(expected); + char *actual = parcURI_ToString(uri); + + assertTrue(strcmp(expected, actual) == 0, + "Expected '%s' actual '%s'", expected, actual); + + parcURI_Release(&uri); + parcMemory_Deallocate((void **) &actual); +} + +LONGBOW_TEST_CASE(parcURI, parseAuthority) +{ + char *authority = "//" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT; + char *expected = URI_AUTHORITY; + + const char *pointer; + char *actual = _parseAuthority(authority, &pointer); + assertTrue(strcmp(expected, actual) == 0, + "Expected '%s' actual '%s'", expected, actual); + assertTrue(*pointer == '/', + "Expected '/' actual '%c'", *pointer); + parcMemory_Deallocate((void **) &actual); +} + +LONGBOW_TEST_CASE(parcURI, parseAuthority_NoAuthority) +{ + char *string = "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT; + + const char *pointer; + char *actual = _parseAuthority(string, &pointer); + assertTrue(actual == NULL, + "Expected NULL actual '%s'", actual); + assertTrue(*pointer == '/', + "Expected '/' actual '%c'", *pointer); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_SetScheme) +{ + char *scheme = "scheme"; + PARCURI *uri = parcURI_Create(); + _parcURI_SetScheme(uri, scheme); + + assertTrue(strcmp(scheme, parcURI_GetScheme(uri)) == 0, + "Expected %s actual %s", scheme, parcURI_GetScheme(uri)); + parcURI_Release(&uri); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_SetScheme_Resetting) +{ + char *scheme = "scheme"; + PARCURI *uri = parcURI_Create(); + _parcURI_SetScheme(uri, scheme); + _parcURI_SetScheme(uri, scheme); + + assertTrue(strcmp(scheme, parcURI_GetScheme(uri)) == 0, + "Expected %s actual %s", scheme, parcURI_GetScheme(uri)); + parcURI_Release(&uri); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_SetScheme_Reset) +{ + char *scheme = "scheme"; + PARCURI *uri = parcURI_Create(); + _parcURI_SetScheme(uri, scheme); + _parcURI_SetScheme(uri, NULL); + + assertNull(parcURI_GetScheme(uri), + "Expected NULL actual %s", parcURI_GetScheme(uri)); + parcURI_Release(&uri); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_SetFragment) +{ + char *fragment = "fragment"; + PARCURI *uri = parcURI_Create(); + _parcURI_SetFragment(uri, fragment); + + assertTrue(strcmp(fragment, parcURI_GetFragment(uri)) == 0, + "Expected %s actual %s", fragment, parcURI_GetFragment(uri)); + parcURI_Release(&uri); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_SetFragment_Resetting) +{ + char *fragment = "fragment"; + PARCURI *uri = parcURI_Create(); + _parcURI_SetFragment(uri, fragment); + _parcURI_SetFragment(uri, fragment); + + assertTrue(strcmp(fragment, parcURI_GetFragment(uri)) == 0, + "Expected %s actual %s", fragment, parcURI_GetFragment(uri)); + parcURI_Release(&uri); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_SetFragment_Reset) +{ + char *fragment = "query"; + PARCURI *uri = parcURI_Create(); + _parcURI_SetFragment(uri, fragment); + _parcURI_SetFragment(uri, NULL); + + assertNull(parcURI_GetFragment(uri), + "Expected NULL actual %s", parcURI_GetFragment(uri)); + parcURI_Release(&uri); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_SetQuery) +{ + char *query = "query"; + PARCURI *uri = parcURI_Create(); + _parcURI_SetQuery(uri, query); + + assertTrue(strcmp(query, parcURI_GetQuery(uri)) == 0, + "Expected %s actual %s", query, parcURI_GetQuery(uri)); + parcURI_Release(&uri); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_SetQuery_Resetting) +{ + char *query = "query"; + PARCURI *uri = parcURI_Create(); + _parcURI_SetQuery(uri, query); + _parcURI_SetQuery(uri, query); + + assertTrue(strcmp(query, parcURI_GetQuery(uri)) == 0, + "Expected %s actual %s", query, parcURI_GetQuery(uri)); + parcURI_Release(&uri); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_SetQuery_Reset) +{ + char *query = "query"; + PARCURI *uri = parcURI_Create(); + _parcURI_SetQuery(uri, query); + _parcURI_SetQuery(uri, NULL); + + assertNull(parcURI_GetQuery(uri), + "Expected NULL actual %s", parcURI_GetQuery(uri)); + parcURI_Release(&uri); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_SetAuthority) +{ + char *authority = "authority@auth"; + PARCURI *uri = parcURI_Create(); + _parcURI_SetAuthority(uri, authority); + + assertTrue(strcmp(authority, parcURI_GetAuthority(uri)) == 0, + "Expected %s actual %s", authority, parcURI_GetAuthority(uri)); + parcURI_Release(&uri); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_SetAuthority_Resetting) +{ + char *authority = "query"; + PARCURI *uri = parcURI_Create(); + _parcURI_SetAuthority(uri, authority); + _parcURI_SetAuthority(uri, authority); + + assertTrue(strcmp(authority, parcURI_GetAuthority(uri)) == 0, + "Expected %s actual %s", authority, parcURI_GetAuthority(uri)); + parcURI_Release(&uri); +} + +LONGBOW_TEST_CASE(parcURI, parcURI_SetAuthority_Reset) +{ + char *query = "query"; + PARCURI *uri = parcURI_Create(); + _parcURI_SetAuthority(uri, query); + _parcURI_SetAuthority(uri, NULL); + + assertNull(parcURI_GetAuthority(uri), + "Expected NULL actual %s", parcURI_GetAuthority(uri)); + parcURI_Release(&uri); +} + +LONGBOW_TEST_CASE(parcURI, parseAuthority_NoPath) +{ + char *authority = "//" URI_AUTHORITY; + char *expected = URI_AUTHORITY; + + const char *pointer; + char *actual = _parseAuthority(authority, &pointer); + + assertTrue(strcmp(expected, actual) == 0, + "Expected '%s' actual '%s'", authority, actual); + assertTrue(*pointer == 0, + "Expected null actual '%c'", *pointer); + parcMemory_Deallocate((void **) &actual); +} + +LONGBOW_TEST_CASE(parcURI, parseFragment) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(parcURI, parsePath) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(parcURI, parseQuery) +{ + testUnimplemented("This test is unimplemented"); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parcURI); + int status = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(status); +} diff --git a/libparc/parc/algol/test/test_parc_URIAuthority.c b/libparc/parc/algol/test/test_parc_URIAuthority.c new file mode 100644 index 00000000..e6d8196a --- /dev/null +++ b/libparc/parc/algol/test/test_parc_URIAuthority.c @@ -0,0 +1,267 @@ +/* + * 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 "../parc_URIAuthority.c" +#include <stdint.h> + +#include <LongBow/unit-test.h> + +#include <parc/algol/parc_URI.h> + +#include "_test_parc_URI.h" + +#include <parc/algol/parc_SafeMemory.h> +#include <parc/testing/parc_ObjectTesting.h> + +LONGBOW_TEST_RUNNER(parcURIAuthority) +{ + LONGBOW_RUN_TEST_FIXTURE(parcURIAuthority); +} + +LONGBOW_TEST_RUNNER_SETUP(parcURIAuthority) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(parcURIAuthority) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("Tests leak memory by %d allocations\n", outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(parcURIAuthority) +{ + LONGBOW_RUN_TEST_CASE(parcURIAuthority, parcURIAuthority_Parse); + + LONGBOW_RUN_TEST_CASE(parcURIAuthority, parcURIAuthority_Acquire); + + LONGBOW_RUN_TEST_CASE(parcURIAuthority, parcURIAuthority_Equals); + + LONGBOW_RUN_TEST_CASE(parcURIAuthority, parcURIAuthority_GetUserInfo); + LONGBOW_RUN_TEST_CASE(parcURIAuthority, parcURIAuthority_GetHostName); + LONGBOW_RUN_TEST_CASE(parcURIAuthority, parcURIAuthority_GetPort); +} + +LONGBOW_TEST_FIXTURE_SETUP(parcURIAuthority) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(parcURIAuthority) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(parcURIAuthority, parcURIAuthority_Parse) +{ + char *uriString = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT; + + uriString = parcMemory_StringDuplicate(uriString, strlen(uriString)); + + PARCURI *uri = parcURI_Parse(uriString); + + PARCURIAuthority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri)); + + assertEqualStrings(parcURIAuthority_GetUserInfo(authority), URI_AUTHORITY_USERINFO); + + parcURIAuthority_Release(&authority); + + parcMemory_Deallocate((void **) &uriString); + parcURI_Release(&uri); + + // URI without the port + uriString = URI_SCHEME "://" URI_AUTHORITY_USERINFO "@" URI_AUTHORITY_HOSTNAME "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT; + uriString = parcMemory_StringDuplicate(uriString, strlen(uriString)); + uri = parcURI_Parse(uriString); + authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri)); + + assertEqualStrings(parcURIAuthority_GetUserInfo(authority), URI_AUTHORITY_USERINFO); + + parcURIAuthority_Release(&authority); + parcURI_Release(&uri); + + // URI with literal V4 address + uriString = URI_SCHEME "://" URI_AUTHORITY_LITERAL_HOST "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT; + uriString = parcMemory_StringDuplicate(uriString, strlen(uriString)); + uri = parcURI_Parse(uriString); + authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri)); + + assertEqualStrings(parcURIAuthority_GetHostName(authority), URI_AUTHORITY_LITERAL_HOSTNAME); + + parcURIAuthority_Release(&authority); + parcURI_Release(&uri); + + // URI with literal V6 address + uriString = URI_SCHEME "://" URI_AUTHORITY_LITERAL_HOST6 "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT; + uriString = parcMemory_StringDuplicate(uriString, strlen(uriString)); + uri = parcURI_Parse(uriString); + authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri)); + + assertEqualStrings(parcURIAuthority_GetHostName(authority), URI_AUTHORITY_LITERAL_HOSTNAME6); + + parcURIAuthority_Release(&authority); + parcURI_Release(&uri); + + // URI with full literal V6 address + uriString = URI_SCHEME "://" URI_AUTHORITY_LITERAL_HOST6_2 "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT; + uriString = parcMemory_StringDuplicate(uriString, strlen(uriString)); + uri = parcURI_Parse(uriString); + authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri)); + + assertEqualStrings(parcURIAuthority_GetHostName(authority), URI_AUTHORITY_LITERAL_HOSTNAME6_2); + + parcURIAuthority_Release(&authority); + parcURI_Release(&uri); + + parcMemory_Deallocate((void **) &uriString); +} + +LONGBOW_TEST_CASE(parcURIAuthority, parcURIAuthority_Acquire) +{ + char *uriString = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT; + + uriString = parcMemory_StringDuplicate(uriString, strlen(uriString)); + + PARCURI *uri = parcURI_Parse(uriString); + + PARCURIAuthority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri)); + PARCURIAuthority *handle = parcURIAuthority_Acquire(authority); + + assertTrue(parcURIAuthority_Equals(authority, handle), "URI Authorities should be equal since they refer to the same object."); + + parcURIAuthority_Release(&authority); + parcURIAuthority_Release(&handle); + + parcMemory_Deallocate((void **) &uriString); + parcURI_Release(&uri); +} + +LONGBOW_TEST_CASE(parcURIAuthority, parcURIAuthority_Equals) +{ + char *uriString1 = URI_SCHEME "://" URI_AUTHORITY; + uriString1 = parcMemory_StringDuplicate(uriString1, strlen(uriString1)); + PARCURI *uri1 = parcURI_Parse(uriString1); + PARCURIAuthority *x = parcURIAuthority_Parse(parcURI_GetAuthority(uri1)); + + char *uriString2 = URI_SCHEME "://" URI_AUTHORITY; + uriString2 = parcMemory_StringDuplicate(uriString2, strlen(uriString2)); + PARCURI *uri2 = parcURI_Parse(uriString2); + PARCURIAuthority *y = parcURIAuthority_Parse(parcURI_GetAuthority(uri2)); + + char *uriString3 = URI_SCHEME "://" URI_AUTHORITY; + uriString3 = parcMemory_StringDuplicate(uriString3, strlen(uriString3)); + PARCURI *uri3 = parcURI_Parse(uriString3); + PARCURIAuthority *z = parcURIAuthority_Parse(parcURI_GetAuthority(uri3)); + + char *differentUriString = URI_SCHEME "://" URI_AUTHORITY_USERINFO; + differentUriString = parcMemory_StringDuplicate(differentUriString, strlen(differentUriString)); + PARCURI *unequalUri = parcURI_Parse(differentUriString); + PARCURIAuthority *u = parcURIAuthority_Parse(parcURI_GetAuthority(unequalUri)); + + char *uriString5 = URI_SCHEME "://" URI_AUTHORITY_DIFFERENT_PORT; + uriString5 = parcMemory_StringDuplicate(uriString5, strlen(uriString5)); + PARCURI *unequalUri5 = parcURI_Parse(uriString5); + PARCURIAuthority *u5 = parcURIAuthority_Parse(parcURI_GetAuthority(unequalUri5)); + + char *uriString4 = URI_SCHEME "://" URI_AUTHORITY_DIFFERENT_USER; + uriString4 = parcMemory_StringDuplicate(uriString4, strlen(uriString4)); + PARCURI *unequalUri4 = parcURI_Parse(uriString4); + PARCURIAuthority *u4 = parcURIAuthority_Parse(parcURI_GetAuthority(unequalUri4)); + + parcObjectTesting_AssertEqualsFunction(parcURIAuthority_Equals, x, y, z, u); + + assertFalse(parcURIAuthority_Equals(x, u4), "Expected URI authorities with different user info to be unequal"); + assertFalse(parcURIAuthority_Equals(x, u5), "Expected URI authorities with different hsot names to be unequal"); + + parcURIAuthority_Release(&x); + parcURIAuthority_Release(&y); + parcURIAuthority_Release(&z); + parcURIAuthority_Release(&u); + parcURIAuthority_Release(&u4); + parcURIAuthority_Release(&u5); + + parcMemory_Deallocate((void **) &uriString1); + parcMemory_Deallocate((void **) &uriString2); + parcMemory_Deallocate((void **) &uriString3); + parcMemory_Deallocate((void **) &uriString4); + parcMemory_Deallocate((void **) &uriString5); + parcMemory_Deallocate((void **) &differentUriString); + + parcURI_Release(&uri1); + parcURI_Release(&uri2); + parcURI_Release(&uri3); + parcURI_Release(&unequalUri); + parcURI_Release(&unequalUri4); + parcURI_Release(&unequalUri5); +} + +LONGBOW_TEST_CASE(parcURIAuthority, parcURIAuthority_GetUserInfo) +{ + char *uriString = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT; + uriString = parcMemory_StringDuplicate(uriString, strlen(uriString)); + PARCURI *uri = parcURI_Parse(uriString); + PARCURIAuthority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri)); + + assertTrue(strcmp(URI_AUTHORITY_USERINFO, parcURIAuthority_GetUserInfo(authority)) == 0, "URI Authority user info should be equal: %s - %s", URI_AUTHORITY_USERINFO, parcURIAuthority_GetUserInfo(authority)); + + parcURIAuthority_Release(&authority); + + parcMemory_Deallocate((void **) &uriString); + parcURI_Release(&uri); +} + +LONGBOW_TEST_CASE(parcURIAuthority, parcURIAuthority_GetHostName) +{ + char *uriString = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT; + uriString = parcMemory_StringDuplicate(uriString, strlen(uriString)); + PARCURI *uri = parcURI_Parse(uriString); + PARCURIAuthority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri)); + + assertTrue(strcmp(URI_AUTHORITY_HOSTNAME, parcURIAuthority_GetHostName(authority)) == 0, "URI Authority host name should be equal: %s - %s", URI_AUTHORITY_HOSTNAME, parcURIAuthority_GetHostName(authority)); + + parcURIAuthority_Release(&authority); + + parcMemory_Deallocate((void **) &uriString); + parcURI_Release(&uri); +} + +LONGBOW_TEST_CASE(parcURIAuthority, parcURIAuthority_GetPort) +{ + char *uriString = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT; + uriString = parcMemory_StringDuplicate(uriString, strlen(uriString)); + PARCURI *uri = parcURI_Parse(uriString); + PARCURIAuthority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri)); + + assertTrue(atol(URI_AUTHORITY_PORT_1) == parcURIAuthority_GetPort(authority), + "URI Authority host name should be equal: %ld - %ld", atol(URI_AUTHORITY_PORT_1), parcURIAuthority_GetPort(authority)); + + parcURIAuthority_Release(&authority); + + parcMemory_Deallocate((void **) &uriString); + parcURI_Release(&uri); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parcURIAuthority); + int status = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(status); +} diff --git a/libparc/parc/algol/test/test_parc_URIPath.c b/libparc/parc/algol/test/test_parc_URIPath.c new file mode 100644 index 00000000..29f34a96 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_URIPath.c @@ -0,0 +1,406 @@ +/* + * 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 "../parc_URIPath.c" +#include <stdint.h> + +#include <LongBow/unit-test.h> + +#include <parc/algol/parc_URI.h> + +#include "_test_parc_URI.h" + +#include <parc/algol/parc_SafeMemory.h> +#include <parc/testing/parc_ObjectTesting.h> + +LONGBOW_TEST_RUNNER(parcURIPath) +{ + LONGBOW_RUN_TEST_FIXTURE(parcURIPath); +} + +LONGBOW_TEST_RUNNER_SETUP(parcURIPath) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(parcURIPath) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("Tests leak memory by %d allocations\n", outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(parcURIPath) +{ + LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Acquire); + LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Parse); + LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Parse_WithQuery); + LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Release); + LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Count); + LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Append); + LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_ToString); + LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Length); + LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Trim); + LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Copy); + LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Equals); + LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Compare_Identity); + LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Compare_Equal); + LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Compare_Unequal); + LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Compose); + LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_StartsWith); + LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_StartsWith_Equal); + LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_StartsWith_Fail); + LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_BuildString); +} + +LONGBOW_TEST_FIXTURE_SETUP(parcURIPath) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(parcURIPath) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Acquire) +{ + const char *pointer; + PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "//////" URI_PATH_SEGMENT, &pointer); + PARCURIPath *handle = parcURIPath_Acquire(path); + + assertTrue(parcURIPath_Equals(path, handle), "URI paths should be equal: %s - %s", parcURIPath_ToString(path), parcURIPath_ToString(handle)); + + parcURIPath_Release(&path); + parcURIPath_Release(&handle); +} + +LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Parse) +{ + const char *pointer; + PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "//////" URI_PATH_SEGMENT, &pointer); + assertNotNull(path, "Expected non-null result."); + assertTrue(*pointer == 0, "Expected pointer to point to the null terminating byte."); + + char *actualPath = parcURIPath_ToString(path); + + char *expectedPath = URI_PATH_SEGMENT "/" URI_PATH_SEGMENT; + assertTrue(strcmp(expectedPath, actualPath) == 0, "Expected %s actual %s", expectedPath, actualPath); + + parcMemory_Deallocate((void **) &actualPath); + parcURIPath_Release(&path); +} + +LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Release) +{ + const char *pointer; + PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT, &pointer); + assertNotNull(path, "Expected non-null result."); + parcURIPath_Release(&path); + assertNull(path, "Expected destroy to null the pointer."); +} + +LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Parse_WithQuery) +{ + const char *pointer; + PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer); + assertNotNull(path, "Expected non-null result."); + assertTrue(*pointer == '?', "Expected pointer to point to the terminating character."); + + char *actualPath = parcURIPath_ToString(path); + char *expectedPath = URI_PATH_SEGMENT "/" URI_PATH_SEGMENT; + assertTrue(strcmp(expectedPath, actualPath) == 0, "Expected %s actual %s", expectedPath, actualPath); + parcMemory_Deallocate((void **) &actualPath); + parcURIPath_Release(&path); +} + +LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Equals) +{ + const char *pointer; + PARCURIPath *x = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer); + PARCURIPath *y = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer); + PARCURIPath *z = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer); + PARCURIPath *u1 = parcURIPath_Parse("/" URI_PATH_SEGMENT "a/" URI_PATH_SEGMENT "?query", &pointer); + PARCURIPath *u2 = parcURIPath_Parse("/" URI_PATH_SEGMENT "?query", &pointer); + + parcObjectTesting_AssertEqualsFunction(parcURIPath_Equals, x, y, z, u1, u2); + + parcURIPath_Release(&x); + parcURIPath_Release(&y); + parcURIPath_Release(&z); + parcURIPath_Release(&u1); + parcURIPath_Release(&u2); +} + +LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Copy) +{ + const char *pointer; + PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer); + PARCURIPath *copy = parcURIPath_Copy(path); + + assertTrue(copy != path, "Expected distinct instances of the path."); + + int comparison = parcURIPath_Compare(path, copy); + + assertTrue(comparison == 0, "Expected the copy to compare equal to the original."); + + parcURIPath_Release(&path); + parcURIPath_Release(©); +} + +LONGBOW_TEST_CASE(parcURIPath, parcURIPath_StartsWith) +{ + const char *pointer; + PARCURIPath *base = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer); + PARCURIPath *prefix = parcURIPath_Parse("/" URI_PATH_SEGMENT "?query", &pointer); + + bool actual = parcURIPath_StartsWith(base, prefix); + + assertTrue(actual, "Expected true, actual false."); + + parcURIPath_Release(&prefix); + parcURIPath_Release(&base); +} + +LONGBOW_TEST_CASE(parcURIPath, parcURIPath_StartsWith_Equal) +{ + const char *pointer; + PARCURIPath *base = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer); + PARCURIPath *prefix = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer); + + bool actual = parcURIPath_StartsWith(base, prefix); + + assertTrue(actual, "Expected true, actual false."); + + parcURIPath_Release(&prefix); + parcURIPath_Release(&base); +} + +LONGBOW_TEST_CASE(parcURIPath, parcURIPath_StartsWith_Fail) +{ + const char *pointer; + PARCURIPath *base = parcURIPath_Parse("/" URI_PATH_SEGMENT "?query", &pointer); + PARCURIPath *prefix1 = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer); + PARCURIPath *prefix2 = parcURIPath_Parse("/" URI_PATH_SEGMENT "A?query", &pointer); + + assertFalse(parcURIPath_StartsWith(base, prefix1), + "Expected false, actual true"); + + assertFalse(parcURIPath_StartsWith(base, prefix2), + "Expected false, actual true"); + + parcURIPath_Release(&prefix1); + parcURIPath_Release(&prefix2); + parcURIPath_Release(&base); +} + +LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Compose) +{ + const char *pointer; + PARCURIPath *base = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer); + PARCURIPath *expected = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer); + + PARCURISegment *a = parcURISegment_Parse(URI_PATH_SEGMENT, &pointer); + PARCURIPath *actual = parcURIPath_Compose(base, a, a, NULL); + parcURISegment_Release(&a); + + char *actualString = parcURIPath_ToString(actual); + char *expectedString = parcURIPath_ToString(expected); + assertTrue(parcURIPath_Compare(expected, actual) == 0, "Expected '%s' actual '%s'\n", expectedString, actualString); + + parcMemory_Deallocate((void **) &actualString); + parcMemory_Deallocate((void **) &expectedString); + + parcURIPath_Release(&actual); + + parcURIPath_Release(&expected); + parcURIPath_Release(&base); +} + +LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Compare_Identity) +{ + const char *pointer; + PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer); + + PARCURIPath *equivalents[] = { + path, + parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query",&pointer), + NULL, + }; + PARCURIPath *lessers[] = { + parcURIPath_Parse("/" URI_PATH_SEGMENT "?query", &pointer), + NULL, + }; + PARCURIPath *greaters[] = { + parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer), + parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "AAA?query", &pointer), + NULL, + }; + + parcObjectTesting_AssertCompareTo(parcURIPath_Compare, path, equivalents, lessers, greaters); + + for (int i = 0; equivalents[i] != NULL; i++) { + parcURIPath_Release(&equivalents[i]); + } + for (int i = 0; lessers[i] != NULL; i++) { + parcURIPath_Release(&lessers[i]); + } + for (int i = 0; greaters[i] != NULL; i++) { + parcURIPath_Release(&greaters[i]); + } +} + +LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Compare_Equal) +{ + const char *pointer; + PARCURIPath *pathA = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer); + PARCURIPath *pathB = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer); + + int comparison = parcURIPath_Compare(pathA, pathB); + + assertTrue(comparison == 0, "Expected 0: equal paths to compare equal. Actual %d", comparison); + parcURIPath_Release(&pathA); + parcURIPath_Release(&pathB); +} + +LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Compare_Unequal) +{ + const char *pointer; + PARCURIPath *pathA = parcURIPath_Parse("/" URI_PATH_SEGMENT "?query", &pointer); + PARCURIPath *pathB = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer); + + int comparison = parcURIPath_Compare(pathA, pathB); + + assertTrue(comparison < 0, "Expected < 0: path A is less than path B. Actual %d", comparison); + parcURIPath_Release(&pathA); + parcURIPath_Release(&pathB); +} + +LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Count) +{ + const char *pointer; + PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT, &pointer); + assertNotNull(path, "Expected non-null result."); + assertTrue(*pointer == 0, "Expected pointer to point to the null terminating byte."); + + size_t actual = parcURIPath_Count(path); + assertTrue(3 == actual, "Expected %d actual %zd", 3, actual); + + parcURIPath_Release(&path); +} + +LONGBOW_TEST_CASE(parcURIPath, parcURIPath_ToString) +{ + const char *pointer; + PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT, &pointer); + assertNotNull(path, "Expected non-null result."); + assertTrue(*pointer == 0, "Expected pointer to point to the null terminating byte."); + + char *actualString = parcURIPath_ToString(path); + + char *expectedString = URI_PATH_SEGMENT "/" URI_PATH_SEGMENT; + assertTrue(strcmp(expectedString, actualString) == 0, "Expected %s actual %s", expectedString, actualString); + + parcMemory_Deallocate((void **) &actualString); + parcURIPath_Release(&path); +} + +LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Length) +{ + const char *pointer; + PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT, &pointer); + assertNotNull(path, "Expected non-null result."); + assertTrue(*pointer == 0, "Expected pointer to point to the null terminating byte."); + + size_t actualCount = parcURIPath_Length(path); + + size_t expectedCount = 79; + assertTrue(expectedCount == actualCount, "Expected %zd actual %zd", expectedCount, actualCount); + + parcURIPath_Release(&path); +} + +LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Append) +{ + const char *pointer; + PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT, &pointer); + + PARCURISegment *segment = parcURISegment_Parse(URI_PATH_SEGMENT, &pointer); + + PARCURIPath *result = parcURIPath_Append(path, segment); + assertTrue(result == path, "Expected %p, actual %p", (void *) path, (void *) result); + + size_t actualCount = parcURIPath_Count(path); + assertTrue(3 == actualCount, "Expected 3, actual %zd", actualCount); + + char *actualPath = parcURIPath_ToString(path); + char *expectedPath = URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT; + assertTrue(strcmp(expectedPath, actualPath) == 0, "Expected %s actual %s", expectedPath, actualPath); + + parcMemory_Deallocate((void **) &actualPath); + parcURIPath_Release(&path); +} + +LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Trim) +{ + const char *pointer; + PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT, &pointer); + + parcURIPath_Trim(path, 2); + size_t actualCount = parcURIPath_Count(path); + assertTrue(2 == actualCount, "Expected 2, actual %zd", actualCount); + + parcURIPath_Release(&path); +} + +LONGBOW_TEST_CASE(parcURIPath, parcURIPath_BuildString) +{ + const char *pointer; + PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT, &pointer); + PARCBufferComposer *target = parcBufferComposer_Create(); + + PARCBufferComposer *string = parcBufferComposer_Create(); + parcBufferComposer_PutString(string, URI_PATH_SEGMENT); + + PARCBuffer *b1 = parcBufferComposer_ProduceBuffer(string); + char *string1 = parcBuffer_ToString(b1); + parcBuffer_Release(&b1); + + parcURIPath_BuildString(path, target); + PARCBuffer *b2 = parcBufferComposer_ProduceBuffer(target); + char *string2 = parcBuffer_ToString(b2); + parcBuffer_Release(&b2); + + assertTrue(strncmp(string1, string2, strlen(string1)) == 0, "String representations of the paths should be equal: %s - %s", string1, string2); + + parcMemory_Deallocate((void **) &string1); + parcMemory_Deallocate((void **) &string2); + + parcBufferComposer_Release(&string); + parcBufferComposer_Release(&target); + parcURIPath_Release(&path); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parcURIPath); + int status = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(status); +} diff --git a/libparc/parc/algol/test/test_parc_URISegment.c b/libparc/parc/algol/test/test_parc_URISegment.c new file mode 100644 index 00000000..640bab89 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_URISegment.c @@ -0,0 +1,315 @@ +/* + * 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 "../parc_URISegment.c" +#include <LongBow/unit-test.h> + +#include <stdint.h> + +#include <parc/algol/parc_URI.h> + +#include "_test_parc_URI.h" + +#include <parc/algol/parc_SafeMemory.h> +#include <parc/testing/parc_ObjectTesting.h> + +LONGBOW_TEST_RUNNER(parcURISegment) +{ + LONGBOW_RUN_TEST_FIXTURE(parcURISegment); +} + +LONGBOW_TEST_RUNNER_SETUP(parcURISegment) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(parcURISegment) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("Tests leak memory by %d allocations\n", outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(parcURISegment) +{ + LONGBOW_RUN_TEST_CASE(parcURISegment, _parcURISegment_fromHexDigit); + LONGBOW_RUN_TEST_CASE(parcURISegment, _parcURISegment_parsePercentEncoded); + + LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Acquire); + LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Create); + LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Parse); + LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Parse_WithExtraSlashes); + LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Parse_WithInvalidPercentage); + LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Release); + LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Length); + LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_ToString); + LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Equals_Contract); + LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Compare_Contract); + LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Clone); + LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_GetBuffer); +} + +LONGBOW_TEST_FIXTURE_SETUP(parcURISegment) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(parcURISegment) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(parcURISegment, _parcURISegment_fromHexDigit) +{ + const char test = 'G'; + signed char actual = _fromHexDigit(test); + assertTrue(-1 == (int) actual, "Invalid hex digit should not be changed to a decimal value, we expect -1 as the result"); +} + +LONGBOW_TEST_CASE(parcURISegment, _parcURISegment_parsePercentEncoded) +{ + unsigned char buffer; + + const char *test1 = "0G"; + const char *result1 = _parsePercentEncoded(test1, &buffer); + assertTrue(NULL == result1, "Expected NULL parsed byte from invalid encoded percentage string, got %s", result1); + const char *test2 = "GG"; + const char *result2 = _parsePercentEncoded(test2, &buffer); + assertTrue(NULL == result2, "Expected NULL parsed byte from invalid encoded percentage string, got %s", result2); + const char *test3 = ""; + const char *result3 = _parsePercentEncoded(test3, &buffer); + assertTrue(NULL == result3, "Expected NULL parsed byte from empty encoded percentage string, got %s", result3); + const char *test4 = "0"; + const char *result4 = _parsePercentEncoded(test4, &buffer); + assertTrue(NULL == result4, "Expected NULL parsed byte from half-empty encoded percentage string, got %s", result4); +} + +LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Acquire) +{ + char *expected = URI_PATH_SEGMENT; + + const char *pointer; + PARCURISegment *segment = parcURISegment_Parse(expected, &pointer); + PARCURISegment *handle = parcURISegment_Acquire(segment); + assertTrue(parcURISegment_Equals(segment, handle), "Expected URI segments to be equal: %s - %s", parcURISegment_ToString(segment), parcURISegment_ToString(handle)); + + parcURISegment_Release(&segment); + parcURISegment_Release(&handle); +} + +LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Create) +{ + char *expected = URI_PATH_SEGMENT; + + PARCURISegment *segment = parcURISegment_Create(strlen(expected), (unsigned char *) expected); + assertNotNull(segment, "Expected non-null result."); + + parcURISegment_Release(&segment); +} + +LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Parse) +{ + char *expected = URI_PATH_SEGMENT; + + const char *pointer; + PARCURISegment *segment = parcURISegment_Parse(expected, &pointer); + assertNotNull(segment, "Expected non-null result."); + + char *expectedBytes = URI_PATH_SEGMENT; + + char *actualBytes = parcURISegment_ToString(segment); + + assertTrue(strcmp(expectedBytes, actualBytes) == 0, + "Expected %s actual %s", expectedBytes, actualBytes); + parcMemory_Deallocate((void **) &actualBytes); + + assertTrue(parcURISegment_Length(segment) == 39, + "Expected 39, actual %zd", parcURISegment_Length(segment)); + assertTrue(*pointer == 0, "Expected pointer to point to the null terminating byte."); + + parcURISegment_Release(&segment); +} + +LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Parse_WithExtraSlashes) +{ + const char *pointer; + PARCURISegment *segment = parcURISegment_Parse(URI_PATH_SEGMENT_WITH_SLASHES, &pointer); + assertNotNull(segment, "Expected non-null result."); + + char *expectedBytes = URI_PATH_SEGMENT; + + char *actualBytes = parcURISegment_ToString(segment); + + assertTrue(strcmp(expectedBytes, actualBytes) == 0, + "Expected %s actual %s", expectedBytes, actualBytes); + parcMemory_Deallocate((void **) &actualBytes); + + assertTrue(parcURISegment_Length(segment) == 39, + "Expected 39, actual %zd", parcURISegment_Length(segment)); + assertTrue(*pointer == '/', "Expected pointer to point to the slash character: %c", *pointer); + + parcURISegment_Release(&segment); +} + +LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Parse_WithInvalidPercentage) +{ + const char *pointer; + PARCURISegment *segment = parcURISegment_Parse(URI_PATH_SEGMENT "%G", &pointer); + + assertNull(segment, "Parsed segment should be NULL since the last percent-encoded byte is invalid"); +} + +LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Release) +{ + char *expected = URI_PATH_SEGMENT; + + const char *pointer; + PARCURISegment *segment = parcURISegment_Parse(expected, &pointer); + assertNotNull(segment, "Expected non-null result."); + + parcURISegment_Release(&segment); + assertNull(segment, "Expected destroy to null the pointer"); +} + +LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Equals_Contract) +{ + char *expected = URI_PATH_SEGMENT; + + const char *pointer; + PARCURISegment *x = parcURISegment_Parse(expected, &pointer); + PARCURISegment *y = parcURISegment_Parse(expected, &pointer); + PARCURISegment *z = parcURISegment_Parse(expected, &pointer); + + parcObjectTesting_AssertEqualsFunction(parcURISegment_Equals, x, y, z, NULL); + + parcURISegment_Release(&x); + parcURISegment_Release(&y); + parcURISegment_Release(&z); +} + +LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Clone) +{ + char *expected = URI_PATH_SEGMENT; + + const char *pointer; + PARCURISegment *segment = parcURISegment_Parse(expected, &pointer); + PARCURISegment *copy = parcURISegment_Clone(segment); + + assertTrue(segment != copy, "Expected different instances of equal segments."); + + int comparison = parcURISegment_Compare(segment, copy); + assertTrue(comparison == 0, "Expected equal segments."); + + assertTrue(parcURISegment_Equals(segment, copy), "Expected equal segments"); + + parcURISegment_Release(©); + parcURISegment_Release(&segment); +} + +LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Length) +{ + const char *pointer; + PARCURISegment *segment = parcURISegment_Parse(URI_PATH_SEGMENT, &pointer); + assertNotNull(segment, + "Expected non-null result."); + assertTrue(*pointer == 0, + "Expected pointer to point to the null terminating byte."); + + size_t actual = parcURISegment_Length(segment); + + assertTrue(actual == 39, + "Expected 39, actual %zd", actual); + + parcURISegment_Release(&segment); +} + +LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Compare_Contract) +{ + const char *pointer; + PARCURISegment *segment = parcURISegment_Parse("MMM", &pointer); + + PARCURISegment *equivalents[] = { + segment, + parcURISegment_Parse("MMM",&pointer), + NULL, + }; + PARCURISegment *lessers[] = { + parcURISegment_Parse("MM", &pointer), + parcURISegment_Parse("MML", &pointer), + NULL, + }; + PARCURISegment *greaters[] = { + parcURISegment_Parse("MMMM", &pointer), + parcURISegment_Parse("MMN", &pointer), + NULL, + }; + parcObjectTesting_AssertCompareTo(parcURISegment_Compare, segment, equivalents, lessers, greaters); + + for (int i = 0; equivalents[i] != NULL; i++) { + parcURISegment_Release(&equivalents[i]); + } + for (int i = 0; lessers[i] != NULL; i++) { + parcURISegment_Release(&lessers[i]); + } + for (int i = 0; greaters[i] != NULL; i++) { + parcURISegment_Release(&greaters[i]); + } +} + +LONGBOW_TEST_CASE(parcURISegment, parcURISegment_ToString) +{ + const char *pointer; + PARCURISegment *segment = parcURISegment_Parse(URI_PATH_SEGMENT, &pointer); + assertNotNull(segment, "Expected non-null result."); + assertTrue(*pointer == 0, "Expected pointer to point to the null terminating byte."); + + char *actual = parcURISegment_ToString(segment); + + assertTrue(strcmp(URI_PATH_SEGMENT, actual) == 0, "Expected %s, actual %s", URI_PATH_SEGMENT, actual); + + parcURISegment_Release(&segment); + + parcMemory_Deallocate((void **) &actual); +} + +LONGBOW_TEST_CASE(parcURISegment, parcURISegment_GetBuffer) +{ + const char *pointer; + PARCURISegment *segment = parcURISegment_Parse(URI_PATH_SEGMENT, &pointer); + assertNotNull(segment, "Expected non-null result."); + assertTrue(*pointer == 0, "Expected pointer to point to the null terminating byte."); + + PARCBuffer *buffer = parcURISegment_GetBuffer(segment); + + char *expected = URI_PATH_SEGMENT; + char *actual = (char *) parcBuffer_Overlay(buffer, 0); + size_t compareLength = strlen(URI_PATH_SEGMENT); + assertTrue(strncmp(expected, actual, compareLength), "Buffer does not contain original data."); + + parcURISegment_Release(&segment); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parcURISegment); + int status = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(status); +} diff --git a/libparc/parc/algol/test/test_parc_Varint.c b/libparc/parc/algol/test/test_parc_Varint.c new file mode 100755 index 00000000..cf0c865c --- /dev/null +++ b/libparc/parc/algol/test/test_parc_Varint.c @@ -0,0 +1,310 @@ +/* + * 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 "../parc_Varint.c" + +#include <LongBow/unit-test.h> + +#include <parc/algol/parc_SafeMemory.h> +#include <parc/algol/parc_BufferComposer.h> + +LONGBOW_TEST_RUNNER(parc_VarInt) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +LONGBOW_TEST_RUNNER_SETUP(parc_VarInt) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(parc_VarInt) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcVarint_And); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_AndUint16); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_AndUint32); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_AndUint64); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_AndUint8); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_AsSize); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_AsUint16); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_AsUint32); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_AsUint64); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_AsUint8); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_Destroy); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_Equals); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_EqualsUint16); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_EqualsUint32); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_EqualsUint64); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_EqualsUint8); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_FromByteBuffer); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_FromUTF8ByteBuffer); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_FromUint32); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_FromUint64); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_FromUint8); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_New); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_Or); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_OrUint16); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_OrUint32); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_OrUint64); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_OrUint8); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_Set); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_ShiftLeft); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_ShiftRight); + LONGBOW_RUN_TEST_CASE(Global, parcVarint_ToString); +} + +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, parcVarint_And) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, parcVarint_AndUint16) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, parcVarint_AndUint32) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, parcVarint_AndUint64) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, parcVarint_AndUint8) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, parcVarint_AsSize) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, parcVarint_AsUint16) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, parcVarint_AsUint32) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, parcVarint_AsUint64) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, parcVarint_AsUint8) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, parcVarint_Destroy) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, parcVarint_Equals) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, parcVarint_EqualsUint16) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, parcVarint_EqualsUint32) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, parcVarint_EqualsUint64) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, parcVarint_EqualsUint8) +{ + unsigned char expected = 5; + PARCVarint *a = parcVarint_FromUint8(expected); + PARCVarint *b = parcVarint_FromUint8(expected); + + assertTrue(parcVarint_Equals(a, b), "Equal instances failed to be equal."); + parcVarint_Destroy(&a); + parcVarint_Destroy(&b); +} + +LONGBOW_TEST_CASE(Global, parcVarint_FromByteBuffer) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, parcVarint_FromUTF8ByteBuffer) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + parcBufferComposer_PutString(composer, "10"); + PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer); + + PARCVarint *varint = parcVarint_FromUTF8ByteBuffer(buffer); + + uint32_t actual = parcVarint_AsUint32(varint); + + assertTrue(10 == actual, "Expected 10 actual %u", actual); + parcBuffer_Release(&buffer); + parcBufferComposer_Release(&composer); + parcVarint_Destroy(&varint); +} + +LONGBOW_TEST_CASE(Global, parcVarint_FromUint32) +{ + uint32_t value = 0x12345678; + PARCVarint *a = parcVarint_FromUint32(value); + assertNotNull(a, "Probably out of memory."); + + uint32_t actual = parcVarint_AsUint32(a); + + assertEqual(value, actual, "%u"); + + parcVarint_Destroy(&a); +} + +LONGBOW_TEST_CASE(Global, parcVarint_FromUint64) +{ + uint64_t value = 0x1234567812345678; + PARCVarint *a = parcVarint_FromUint64(value); + assertNotNull(a, "Probably out of memory."); + + uint64_t actual = parcVarint_AsUint64(a); + + assertEqual(value, actual, "%" PRIu64); + + parcVarint_Destroy(&a); +} + +LONGBOW_TEST_CASE(Global, parcVarint_FromUint8) +{ + uint8_t value = 0x12; + PARCVarint *a = parcVarint_FromUint8(value); + assertNotNull(a, "Probably out of memory."); + + uint8_t actual = parcVarint_AsUint8(a); + + assertEqual(value, actual, "%d"); + + parcVarint_Destroy(&a); +} + +LONGBOW_TEST_CASE(Global, parcVarint_New) +{ + PARCVarint *a = parcVarint_Create(); + assertNotNull(a, "Probably out of memory."); + + parcVarint_Destroy(&a); + assertNull(a, "Destroy failed to nullify."); +} + +LONGBOW_TEST_CASE(Global, parcVarint_Or) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, parcVarint_OrUint16) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, parcVarint_OrUint32) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, parcVarint_OrUint64) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, parcVarint_OrUint8) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, parcVarint_Set) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, parcVarint_ShiftLeft) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, parcVarint_ShiftRight) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, parcVarint_ToString) +{ + 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[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_VarInt); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/algol/test/test_parc_Vector.c b/libparc/parc/algol/test/test_parc_Vector.c new file mode 100644 index 00000000..bea435dc --- /dev/null +++ b/libparc/parc/algol/test/test_parc_Vector.c @@ -0,0 +1,116 @@ +/* + * 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 <LongBow/unit-test.h> +#include <LongBow/debugging.h> + +#include <parc/algol/parc_SafeMemory.h> + +#include "../parc_Vector.c" + +LONGBOW_TEST_RUNNER(PARCVector) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +LONGBOW_TEST_RUNNER_SETUP(PARCVector) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(PARCVector) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("Tests leak memory by %d allocations\n", outstandingAllocations); + exit(1); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcVectorDestroy); + LONGBOW_RUN_TEST_CASE(Global, parcVectorGetLength); + LONGBOW_RUN_TEST_CASE(Global, parcVectorGetPointer); + LONGBOW_RUN_TEST_CASE(Global, parcVectorCreate); +} + +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, parcVectorDestroy) +{ + const char *string = "Hello World"; + + PARCVector *x = parcVector_Create((void *) string, strlen(string)); + parcVector_Destroy(&x); + assertNull(x, "Destroy did not nullify."); +} + +LONGBOW_TEST_CASE(Global, parcVectorGetLength) +{ + const char *string = "Hello World"; + + PARCVector *x = parcVector_Create((void *) string, strlen(string)); + size_t expected = strlen(string); + size_t actual = parcVector_GetLength(x); + assertEqual(expected, actual, "%zd"); + parcVector_Destroy(&x); +} + +LONGBOW_TEST_CASE(Global, parcVectorGetPointer) +{ + const char *expected = "Hello World"; + + PARCVector *x = parcVector_Create((void *) expected, strlen(expected)); + const char *actual = parcVector_GetPointer(x); + + assertEqual((void *) expected, (void *) actual, "%p"); + + parcVector_Destroy(&x); +} + +LONGBOW_TEST_CASE(Global, parcVectorCreate) +{ + const char *string = "Hello World"; + + PARCVector *x = parcVector_Create((void *) string, strlen(string)); + assertNotNull(x, "Probably out of memory."); + parcVector_Destroy(&x); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(PARCVector); + int status = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(status); +} |