{"action":"created","comment":{"url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/pulls/comments/37977345","id":37977345,"diff_hunk":"@@ -168,6 +168,120 @@ Running `build` also runs all the unit tests:\n ./gradlew build\n ```\n \n+### Cross Platform Testing\n+The plugin is designed to work on Mac OS X but also has limited support on Windows and Linux.\n+The unit tests are designed to run across all platforms. This minimizes the chance that a\n+developer working on one platform can break the build on another platform.\n+\n+#### Separators\n+The main issue working across platforms is separators. For the \"file separator\", this\n+separates a directory hierarchy: `java.io.File.separator`. This is `/` on Linux and\n+Mac OS X and `\\` on Windows. For the \"path separator\", this is the boundary between\n+paths on the command line: `java.io.File.pathSeparator`. This is `:` on Linux and Mac OS X\n+and `;` on Windows.\n+\n+All the tests should be written using forward slashes (the standard for Linux and Mac OS X).\n+MockProjectExec and other code will automatically convert `\\` to `/` **on Windows only**.\n+\n+#### Absolute Paths\n+Absolute path detection is usually down by checking if it `startswith('/')`. For Windows,\n+an absolute path has to start with the volume, e.g. `C:\\`. When passing absolute paths\n+to `proj.file(...)`, it must be prefixed with `C:` (the only volume used in testing).\n+That should be done by using `TestingUtils.windowsNoFakeAbsolutePath(...)`. The following\n+is a simple example that tests the OS specific behaviour of `proj.file(...)`:\n+\n+```groovy\n+@Test\n+public void testProjFile() {\n+    String absolutePath = TestingUtils.windowsNoFakeAbsolutePath('/ABSOLUTE_PATH')\n+    String actual = proj.file(absolutePath).absolutePath\n+    // proj.file on Windows will convert '/' to '\\', so convert back again\n+    assert absolutePath == TestingUtils.windowsToForwardSlash(actual)\n+}\n+```\n+\n+#### Command Lines\n+Windows doesn't support `echo hello` directly, instead you must run `cmd /C echo hello`.\n+The `demandExecAndReturn(...)` methods allow you to supply a substitute set of arguments\n+to replace the initial executable. For example the following will typically test for the\n+execution of the command: `echo hello`. On Windows however, it will replace the first\n+element with the second array, testing for the command `cmd /C echo hello`.\n+\n+```groovy\n+mockProjectExec.demandExecAndReturn(\n+        ['echo', 'hello'],\n+        // windows substitute args\n+        ['cmd', '/C', 'echo'])\n+```\n+\n+#### Fake OS\n+To get better coverage for a particular OS, without needing a separate native build,\n+it is possible to use the `setFakeOSXXXX()` methods. This has limited functionality\n+and won't replace the native separators as used by java.io.File. When this is used,\n+the `@Before` test method should always use the reset `setFakeOSNone()` to make the\n+unit tests more hermetic. Within the particular test, use `Utils.setFakeOSWindows()`\n+or similar for Linux or Mac OS X.\n+\n+In order for the test to pass, the main code under test must use `Utils.fileSeparator()`\n+and `Utils.pathSeparator()`. These methods will respect the setFakeOSXXXX methods\n+and return the separators for the faked OS.\n+\n+Adding in a line for `Utils.setFakeOSWindows()` in the above example would force it","path":"CONTRIBUTING.md","position":62,"original_position":62,"commit_id":"e28cc30e52d8f6c5746aab2a5f488d5a918fd809","original_commit_id":"e28cc30e52d8f6c5746aab2a5f488d5a918fd809","user":{"login":"advayDev1","id":11729521,"avatar_url":"https://avatars.githubusercontent.com/u/11729521?v=3","gravatar_id":"","url":"https://api.github.com/users/advayDev1","html_url":"https://github.com/advayDev1","followers_url":"https://api.github.com/users/advayDev1/followers","following_url":"https://api.github.com/users/advayDev1/following{/other_user}","gists_url":"https://api.github.com/users/advayDev1/gists{/gist_id}","starred_url":"https://api.github.com/users/advayDev1/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/advayDev1/subscriptions","organizations_url":"https://api.github.com/users/advayDev1/orgs","repos_url":"https://api.github.com/users/advayDev1/repos","events_url":"https://api.github.com/users/advayDev1/events{/privacy}","received_events_url":"https://api.github.com/users/advayDev1/received_events","type":"User","site_admin":false},"body":"which above example?  do you mean the example below?","created_at":"2015-08-26T12:54:59Z","updated_at":"2015-08-26T12:54:59Z","html_url":"https://github.com/j2objc-contrib/j2objc-gradle/pull/424#discussion_r37977345","pull_request_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/pulls/424","_links":{"self":{"href":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/pulls/comments/37977345"},"html":{"href":"https://github.com/j2objc-contrib/j2objc-gradle/pull/424#discussion_r37977345"},"pull_request":{"href":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/pulls/424"}}},"pull_request":{"url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/pulls/424","id":43389537,"html_url":"https://github.com/j2objc-contrib/j2objc-gradle/pull/424","diff_url":"https://github.com/j2objc-contrib/j2objc-gradle/pull/424.diff","patch_url":"https://github.com/j2objc-contrib/j2objc-gradle/pull/424.patch","issue_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/issues/424","number":424,"state":"open","locked":false,"title":"Cross Platform Testing","user":{"login":"brunobowden","id":679339,"avatar_url":"https://avatars.githubusercontent.com/u/679339?v=3","gravatar_id":"","url":"https://api.github.com/users/brunobowden","html_url":"https://github.com/brunobowden","followers_url":"https://api.github.com/users/brunobowden/followers","following_url":"https://api.github.com/users/brunobowden/following{/other_user}","gists_url":"https://api.github.com/users/brunobowden/gists{/gist_id}","starred_url":"https://api.github.com/users/brunobowden/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/brunobowden/subscriptions","organizations_url":"https://api.github.com/users/brunobowden/orgs","repos_url":"https://api.github.com/users/brunobowden/repos","events_url":"https://api.github.com/users/brunobowden/events{/privacy}","received_events_url":"https://api.github.com/users/brunobowden/received_events","type":"User","site_admin":false},"body":"- Explain how to develop cross platform\r\n- Notes on separators, absolute paths, command line and faking the OS","created_at":"2015-08-26T11:05:18Z","updated_at":"2015-08-26T12:54:59Z","closed_at":null,"merged_at":null,"merge_commit_sha":"b8b5cea385c0e0cee9dddb1c70623f7a05ab14cb","assignee":{"login":"advayDev1","id":11729521,"avatar_url":"https://avatars.githubusercontent.com/u/11729521?v=3","gravatar_id":"","url":"https://api.github.com/users/advayDev1","html_url":"https://github.com/advayDev1","followers_url":"https://api.github.com/users/advayDev1/followers","following_url":"https://api.github.com/users/advayDev1/following{/other_user}","gists_url":"https://api.github.com/users/advayDev1/gists{/gist_id}","starred_url":"https://api.github.com/users/advayDev1/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/advayDev1/subscriptions","organizations_url":"https://api.github.com/users/advayDev1/orgs","repos_url":"https://api.github.com/users/advayDev1/repos","events_url":"https://api.github.com/users/advayDev1/events{/privacy}","received_events_url":"https://api.github.com/users/advayDev1/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/pulls/424/commits","review_comments_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/pulls/424/comments","review_comment_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/pulls/comments{/number}","comments_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/issues/424/comments","statuses_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/statuses/e28cc30e52d8f6c5746aab2a5f488d5a918fd809","head":{"label":"brunobowden:docs","ref":"docs","sha":"e28cc30e52d8f6c5746aab2a5f488d5a918fd809","user":{"login":"brunobowden","id":679339,"avatar_url":"https://avatars.githubusercontent.com/u/679339?v=3","gravatar_id":"","url":"https://api.github.com/users/brunobowden","html_url":"https://github.com/brunobowden","followers_url":"https://api.github.com/users/brunobowden/followers","following_url":"https://api.github.com/users/brunobowden/following{/other_user}","gists_url":"https://api.github.com/users/brunobowden/gists{/gist_id}","starred_url":"https://api.github.com/users/brunobowden/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/brunobowden/subscriptions","organizations_url":"https://api.github.com/users/brunobowden/orgs","repos_url":"https://api.github.com/users/brunobowden/repos","events_url":"https://api.github.com/users/brunobowden/events{/privacy}","received_events_url":"https://api.github.com/users/brunobowden/received_events","type":"User","site_admin":false},"repo":{"id":37033994,"name":"j2objc-gradle","full_name":"brunobowden/j2objc-gradle","owner":{"login":"brunobowden","id":679339,"avatar_url":"https://avatars.githubusercontent.com/u/679339?v=3","gravatar_id":"","url":"https://api.github.com/users/brunobowden","html_url":"https://github.com/brunobowden","followers_url":"https://api.github.com/users/brunobowden/followers","following_url":"https://api.github.com/users/brunobowden/following{/other_user}","gists_url":"https://api.github.com/users/brunobowden/gists{/gist_id}","starred_url":"https://api.github.com/users/brunobowden/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/brunobowden/subscriptions","organizations_url":"https://api.github.com/users/brunobowden/orgs","repos_url":"https://api.github.com/users/brunobowden/repos","events_url":"https://api.github.com/users/brunobowden/events{/privacy}","received_events_url":"https://api.github.com/users/brunobowden/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/brunobowden/j2objc-gradle","description":"Gradle plugin for j2objc (Java to Objective-C transpiler)","fork":true,"url":"https://api.github.com/repos/brunobowden/j2objc-gradle","forks_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/forks","keys_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/keys{/key_id}","collaborators_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/teams","hooks_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/hooks","issue_events_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/issues/events{/number}","events_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/events","assignees_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/assignees{/user}","branches_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/branches{/branch}","tags_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/tags","blobs_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/git/refs{/sha}","trees_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/git/trees{/sha}","statuses_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/statuses/{sha}","languages_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/languages","stargazers_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/stargazers","contributors_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/contributors","subscribers_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/subscribers","subscription_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/subscription","commits_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/commits{/sha}","git_commits_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/git/commits{/sha}","comments_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/comments{/number}","issue_comment_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/issues/comments{/number}","contents_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/contents/{+path}","compare_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/compare/{base}...{head}","merges_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/merges","archive_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/downloads","issues_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/issues{/number}","pulls_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/pulls{/number}","milestones_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/milestones{/number}","notifications_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/labels{/name}","releases_url":"https://api.github.com/repos/brunobowden/j2objc-gradle/releases{/id}","created_at":"2015-06-07T22:04:38Z","updated_at":"2015-06-18T06:13:01Z","pushed_at":"2015-08-26T11:04:55Z","git_url":"git://github.com/brunobowden/j2objc-gradle.git","ssh_url":"git@github.com:brunobowden/j2objc-gradle.git","clone_url":"https://github.com/brunobowden/j2objc-gradle.git","svn_url":"https://github.com/brunobowden/j2objc-gradle","homepage":null,"size":1234,"stargazers_count":1,"watchers_count":1,"language":"Groovy","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":0,"forks":1,"open_issues":0,"watchers":1,"default_branch":"master"}},"base":{"label":"j2objc-contrib:master","ref":"master","sha":"69f77aab754a5d75e18a76b5788063fd2b266943","user":{"login":"j2objc-contrib","id":12766207,"avatar_url":"https://avatars.githubusercontent.com/u/12766207?v=3","gravatar_id":"","url":"https://api.github.com/users/j2objc-contrib","html_url":"https://github.com/j2objc-contrib","followers_url":"https://api.github.com/users/j2objc-contrib/followers","following_url":"https://api.github.com/users/j2objc-contrib/following{/other_user}","gists_url":"https://api.github.com/users/j2objc-contrib/gists{/gist_id}","starred_url":"https://api.github.com/users/j2objc-contrib/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/j2objc-contrib/subscriptions","organizations_url":"https://api.github.com/users/j2objc-contrib/orgs","repos_url":"https://api.github.com/users/j2objc-contrib/repos","events_url":"https://api.github.com/users/j2objc-contrib/events{/privacy}","received_events_url":"https://api.github.com/users/j2objc-contrib/received_events","type":"Organization","site_admin":false},"repo":{"id":30206593,"name":"j2objc-gradle","full_name":"j2objc-contrib/j2objc-gradle","owner":{"login":"j2objc-contrib","id":12766207,"avatar_url":"https://avatars.githubusercontent.com/u/12766207?v=3","gravatar_id":"","url":"https://api.github.com/users/j2objc-contrib","html_url":"https://github.com/j2objc-contrib","followers_url":"https://api.github.com/users/j2objc-contrib/followers","following_url":"https://api.github.com/users/j2objc-contrib/following{/other_user}","gists_url":"https://api.github.com/users/j2objc-contrib/gists{/gist_id}","starred_url":"https://api.github.com/users/j2objc-contrib/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/j2objc-contrib/subscriptions","organizations_url":"https://api.github.com/users/j2objc-contrib/orgs","repos_url":"https://api.github.com/users/j2objc-contrib/repos","events_url":"https://api.github.com/users/j2objc-contrib/events{/privacy}","received_events_url":"https://api.github.com/users/j2objc-contrib/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/j2objc-contrib/j2objc-gradle","description":"Gradle plugin for j2objc (Java to Objective-C transpiler)","fork":false,"url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle","forks_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/forks","keys_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/keys{/key_id}","collaborators_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/teams","hooks_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/hooks","issue_events_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/issues/events{/number}","events_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/events","assignees_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/assignees{/user}","branches_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/branches{/branch}","tags_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/tags","blobs_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/git/refs{/sha}","trees_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/git/trees{/sha}","statuses_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/statuses/{sha}","languages_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/languages","stargazers_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/stargazers","contributors_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/contributors","subscribers_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/subscribers","subscription_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/subscription","commits_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/commits{/sha}","git_commits_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/git/commits{/sha}","comments_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/comments{/number}","issue_comment_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/issues/comments{/number}","contents_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/contents/{+path}","compare_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/compare/{base}...{head}","merges_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/merges","archive_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/downloads","issues_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/issues{/number}","pulls_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/pulls{/number}","milestones_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/milestones{/number}","notifications_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/labels{/name}","releases_url":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/releases{/id}","created_at":"2015-02-02T20:22:07Z","updated_at":"2015-08-24T20:00:10Z","pushed_at":"2015-08-26T11:05:20Z","git_url":"git://github.com/j2objc-contrib/j2objc-gradle.git","ssh_url":"git@github.com:j2objc-contrib/j2objc-gradle.git","clone_url":"https://github.com/j2objc-contrib/j2objc-gradle.git","svn_url":"https://github.com/j2objc-contrib/j2objc-gradle","homepage":"https://github.com/j2objc-contrib/j2objc-gradle","size":2832,"stargazers_count":47,"watchers_count":47,"language":"Groovy","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":12,"mirror_url":null,"open_issues_count":52,"forks":12,"open_issues":52,"watchers":47,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/pulls/424"},"html":{"href":"https://github.com/j2objc-contrib/j2objc-gradle/pull/424"},"issue":{"href":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/issues/424"},"comments":{"href":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/issues/424/comments"},"review_comments":{"href":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/pulls/424/comments"},"review_comment":{"href":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/pulls/424/commits"},"statuses":{"href":"https://api.github.com/repos/j2objc-contrib/j2objc-gradle/statuses/e28cc30e52d8f6c5746aab2a5f488d5a918fd809"}}}}