{"action":"created","comment":{"url":"https://api.github.com/repos/AutoFixture/AutoFixture/pulls/comments/36495754","id":36495754,"diff_hunk":"@@ -0,0 +1,64 @@\n+﻿using System;\r\n+using Ploeh.AutoFixture.Kernel;\r\n+\r\n+namespace Ploeh.AutoFixture.AutoNSubstitute\r\n+{\r\n+    /// <summary>\r\n+    /// Creates a substitute in response to the <see cref=\"SubstituteRequest\"/>.\r\n+    /// </summary>\r\n+    /// <remarks>\r\n+    /// This class serves as a fixture customization, responding to explicit substitute requests in the form of the\r\n+    /// <see cref=\"SubstituteRequest\"/> instances. The actual construction of the substitute is delegated to a \r\n+    /// substitute constructor, responsible for invoking an appropriate constructor for the target type with\r\n+    /// automatically generated arguments.\r\n+    /// </remarks>\r\n+    public class SubstituteBuilder : ISpecimenBuilder\r\n+    {\r\n+        private readonly ISpecimenBuilder substituteConstructor;\r\n+\r\n+        /// <summary>\r\n+        /// Initializes a new instance of the <see cref=\"SubstituteBuilder\"/> class with the specified \r\n+        /// <paramref name=\"substituteConstructor\"/>.\r\n+        /// </summary>\r\n+        /// <param name=\"substituteConstructor\">\r\n+        /// An <see cref=\"ISpecimenBuilder\"/> responsible for creating a substitute instance from a requested \r\n+        /// <see cref=\"Type\"/>.\r\n+        /// </param>\r\n+        public SubstituteBuilder(ISpecimenBuilder substituteConstructor)\r\n+        {\r\n+            if (substituteConstructor == null)\r\n+            {\r\n+                throw new ArgumentNullException(\"substituteConstructor\");\r\n+            }\r\n+\r\n+            this.substituteConstructor = substituteConstructor;\r\n+        }\r\n+\r\n+        /// <summary>\r\n+        /// Returns an <see cref=\"ISpecimenBuilder\"/> responsible for creating a substitute instance based on a target\r\n+        /// <see cref=\"Type\"/> type.\r\n+        /// </summary>\r\n+        public ISpecimenBuilder SubstituteConstructor \r","path":"Src/AutoNSubstitute/SubstituteBuilder.cs","position":41,"original_position":41,"commit_id":"9809ab24fe714b71a0a0c94f6ef2c44a5c17b176","original_commit_id":"9809ab24fe714b71a0a0c94f6ef2c44a5c17b176","user":{"login":"ploeh","id":242165,"avatar_url":"https://avatars.githubusercontent.com/u/242165?v=3","gravatar_id":"","url":"https://api.github.com/users/ploeh","html_url":"https://github.com/ploeh","followers_url":"https://api.github.com/users/ploeh/followers","following_url":"https://api.github.com/users/ploeh/following{/other_user}","gists_url":"https://api.github.com/users/ploeh/gists{/gist_id}","starred_url":"https://api.github.com/users/ploeh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ploeh/subscriptions","organizations_url":"https://api.github.com/users/ploeh/orgs","repos_url":"https://api.github.com/users/ploeh/repos","events_url":"https://api.github.com/users/ploeh/events{/privacy}","received_events_url":"https://api.github.com/users/ploeh/received_events","type":"User","site_admin":false},"body":"Would `SubstituteFactory` or `SubstituteBuilder` be better names?\r\n\r\nGiven that the type in question is an `ISpecimenBuilder`, there's no guarantee that it'll invoke a constructor...","created_at":"2015-08-07T07:15:40Z","updated_at":"2015-08-07T07:15:40Z","html_url":"https://github.com/AutoFixture/AutoFixture/pull/430#discussion_r36495754","pull_request_url":"https://api.github.com/repos/AutoFixture/AutoFixture/pulls/430","_links":{"self":{"href":"https://api.github.com/repos/AutoFixture/AutoFixture/pulls/comments/36495754"},"html":{"href":"https://github.com/AutoFixture/AutoFixture/pull/430#discussion_r36495754"},"pull_request":{"href":"https://api.github.com/repos/AutoFixture/AutoFixture/pulls/430"}}},"pull_request":{"url":"https://api.github.com/repos/AutoFixture/AutoFixture/pulls/430","id":41373811,"html_url":"https://github.com/AutoFixture/AutoFixture/pull/430","diff_url":"https://github.com/AutoFixture/AutoFixture/pull/430.diff","patch_url":"https://github.com/AutoFixture/AutoFixture/pull/430.patch","issue_url":"https://api.github.com/repos/AutoFixture/AutoFixture/issues/430","number":430,"state":"open","locked":false,"title":"Substitute attribute, ","user":{"login":"olegsych","id":8355091,"avatar_url":"https://avatars.githubusercontent.com/u/8355091?v=3","gravatar_id":"","url":"https://api.github.com/users/olegsych","html_url":"https://github.com/olegsych","followers_url":"https://api.github.com/users/olegsych/followers","following_url":"https://api.github.com/users/olegsych/following{/other_user}","gists_url":"https://api.github.com/users/olegsych/gists{/gist_id}","starred_url":"https://api.github.com/users/olegsych/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/olegsych/subscriptions","organizations_url":"https://api.github.com/users/olegsych/orgs","repos_url":"https://api.github.com/users/olegsych/repos","events_url":"https://api.github.com/users/olegsych/events{/privacy}","received_events_url":"https://api.github.com/users/olegsych/received_events","type":"User","site_admin":false},"body":"The proposed `SubstituteAttribute` enables changing the default fixture behavior and forcing creation of concrete type substitutes for individual test parameters. The implementation follows the pattern established by the `AutoFixture` for data annotation attributes, such as `[Range]`, `[RegularExpression]` and `[StringLength]`.\r\n\r\nThe idea was previously discussed in #132 and submitted in #421. The proposed implementation does _not_ include the previously rejected `AttributeRelay<T>` refactoring #424.\r\n\r\nHere are samples that illustrate this attribute's use:\r\n\r\n```C#\r\n[Theory, AutoDataWithAutoSubstituteCustomization]\r\npublic void ConcreteTypesAreSubstitutedWhenParameterIsMarkedWithSubstituteAttribute(\r\n    [Substitute]ConcreteType t, object obj)\r\n{\r\n    t.VirtualMethod(obj);\r\n    t.Received().VirtualMethod(obj);\r\n}\r\n\r\n[Theory, AutoDataWithAutoSubstituteCustomization]\r\npublic void SubstituteAttributeAppliesToSingleParameterAndNotItsEntireType(\r\n    [Substitute]ConcreteType t1, ConcreteType t2, object obj)\r\n{\r\n    t2.VirtualMethod(obj);\r\n    Assert.Throws<NotASubstituteException>(() => t2.Received().VirtualMethod(obj));\r\n}\r\n```\r\n\r\nApplying the `SubstituteAttribute` to a parameter of a concrete type fails the test, such as the one in example below, _before_ running it.\r\n\r\n```C#\r\n[Theory, AutoDataWithAutoSubstituteCustomization]\r\npublic void AttemptingToSubstituteSealedTypeFailsTestBeforeItStarts(\r\n    [Substitute]SealedType t, object obj)\r\n{\r\n}\r\n```\r\n\r\nApplying the `SubstituteAttribute` in a method with a regular `AutoDataAttribute` results in an obscure failure within the test itself because the attribute has no behavior and requires the `AutoSubstituteCustomization` to be applied to the test's `Fixture`. Below is a sample that illustrates the problem. A separate pull request #418 was started earlier to enable addressing it.\r\n\r\n```C#\r\n[Theory, AutoData]\r\npublic void SubstituteAttributeShouldWorkWithPlainAutoDataAttribute(\r\n    [Substitute]ConcreteType t, object obj)\r\n{\r\n    t.VirtualMethod(obj);\r\n    // The following line throws NotASubstituteExeption, which is confusing because the\r\n    // Substitute attribute is clearly used.\r\n    t.Received().VirtualMethod(obj);\r\n}\r\n```\r\n\r\n### Changes in AutoFixture.NSubstitute\r\n- Implement `SubstituteAttribute`.\r\n- Implement `SubstituteRequest` used to request a substitute of a given type.\r\n- Implement `SubstituteBuilder` to handle substitute requests.\r\n- Implement `SubstituteAttributeRelay` to convert requests for parameters, properties and fields marked with the `SubstituteAttribute` to substitute requests of their respective types.\r\n- Implement `SubstituteRelay` to convert requests for abstract types and interfaces to requests for substitutes.\r\n- Implement `AutoSubstituteCustomization` to encapsulate addition of the new components to an `IFixture`. \r\n\r\n### Open Questions\r\n- [ ] Should the new `SubstituteBuilder` logic be merged into the existing `NSubstituteBuilder`? Note that the new class is meant to be a customization, while the existing class serves as a residue collector.\r\n- [ ] Should the new `AutoSubstituteCustomization` logic be merged into the existing `AutoNSubstituteCustomization` and the `AutoConfiguredNSubstituteCustomization`? I don't foresee any observable behavior changes in pure usage scenarios. However, the existing classes expose internal implementation components through properties and there is a potential that someone might have taken a dependency on them.","created_at":"2015-07-31T19:41:00Z","updated_at":"2015-08-07T07:15:40Z","closed_at":null,"merged_at":null,"merge_commit_sha":"c8fa14cc3aaa8f0f3481d780221106516da6edd4","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/AutoFixture/AutoFixture/pulls/430/commits","review_comments_url":"https://api.github.com/repos/AutoFixture/AutoFixture/pulls/430/comments","review_comment_url":"https://api.github.com/repos/AutoFixture/AutoFixture/pulls/comments{/number}","comments_url":"https://api.github.com/repos/AutoFixture/AutoFixture/issues/430/comments","statuses_url":"https://api.github.com/repos/AutoFixture/AutoFixture/statuses/9809ab24fe714b71a0a0c94f6ef2c44a5c17b176","head":{"label":"olegsych:substitute-attribute","ref":"substitute-attribute","sha":"9809ab24fe714b71a0a0c94f6ef2c44a5c17b176","user":{"login":"olegsych","id":8355091,"avatar_url":"https://avatars.githubusercontent.com/u/8355091?v=3","gravatar_id":"","url":"https://api.github.com/users/olegsych","html_url":"https://github.com/olegsych","followers_url":"https://api.github.com/users/olegsych/followers","following_url":"https://api.github.com/users/olegsych/following{/other_user}","gists_url":"https://api.github.com/users/olegsych/gists{/gist_id}","starred_url":"https://api.github.com/users/olegsych/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/olegsych/subscriptions","organizations_url":"https://api.github.com/users/olegsych/orgs","repos_url":"https://api.github.com/users/olegsych/repos","events_url":"https://api.github.com/users/olegsych/events{/privacy}","received_events_url":"https://api.github.com/users/olegsych/received_events","type":"User","site_admin":false},"repo":{"id":37674496,"name":"AutoFixture","full_name":"olegsych/AutoFixture","owner":{"login":"olegsych","id":8355091,"avatar_url":"https://avatars.githubusercontent.com/u/8355091?v=3","gravatar_id":"","url":"https://api.github.com/users/olegsych","html_url":"https://github.com/olegsych","followers_url":"https://api.github.com/users/olegsych/followers","following_url":"https://api.github.com/users/olegsych/following{/other_user}","gists_url":"https://api.github.com/users/olegsych/gists{/gist_id}","starred_url":"https://api.github.com/users/olegsych/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/olegsych/subscriptions","organizations_url":"https://api.github.com/users/olegsych/orgs","repos_url":"https://api.github.com/users/olegsych/repos","events_url":"https://api.github.com/users/olegsych/events{/privacy}","received_events_url":"https://api.github.com/users/olegsych/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/olegsych/AutoFixture","description":"AutoFixture is an open source library for .NET designed to minimize the 'Arrange' phase of your unit tests in order to maximise maintainability.Its primary goal is to allow developers to focus on what is being tested rather than how to setup the test scenario, by making it easier to create object graphs containing test data.","fork":true,"url":"https://api.github.com/repos/olegsych/AutoFixture","forks_url":"https://api.github.com/repos/olegsych/AutoFixture/forks","keys_url":"https://api.github.com/repos/olegsych/AutoFixture/keys{/key_id}","collaborators_url":"https://api.github.com/repos/olegsych/AutoFixture/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/olegsych/AutoFixture/teams","hooks_url":"https://api.github.com/repos/olegsych/AutoFixture/hooks","issue_events_url":"https://api.github.com/repos/olegsych/AutoFixture/issues/events{/number}","events_url":"https://api.github.com/repos/olegsych/AutoFixture/events","assignees_url":"https://api.github.com/repos/olegsych/AutoFixture/assignees{/user}","branches_url":"https://api.github.com/repos/olegsych/AutoFixture/branches{/branch}","tags_url":"https://api.github.com/repos/olegsych/AutoFixture/tags","blobs_url":"https://api.github.com/repos/olegsych/AutoFixture/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/olegsych/AutoFixture/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/olegsych/AutoFixture/git/refs{/sha}","trees_url":"https://api.github.com/repos/olegsych/AutoFixture/git/trees{/sha}","statuses_url":"https://api.github.com/repos/olegsych/AutoFixture/statuses/{sha}","languages_url":"https://api.github.com/repos/olegsych/AutoFixture/languages","stargazers_url":"https://api.github.com/repos/olegsych/AutoFixture/stargazers","contributors_url":"https://api.github.com/repos/olegsych/AutoFixture/contributors","subscribers_url":"https://api.github.com/repos/olegsych/AutoFixture/subscribers","subscription_url":"https://api.github.com/repos/olegsych/AutoFixture/subscription","commits_url":"https://api.github.com/repos/olegsych/AutoFixture/commits{/sha}","git_commits_url":"https://api.github.com/repos/olegsych/AutoFixture/git/commits{/sha}","comments_url":"https://api.github.com/repos/olegsych/AutoFixture/comments{/number}","issue_comment_url":"https://api.github.com/repos/olegsych/AutoFixture/issues/comments{/number}","contents_url":"https://api.github.com/repos/olegsych/AutoFixture/contents/{+path}","compare_url":"https://api.github.com/repos/olegsych/AutoFixture/compare/{base}...{head}","merges_url":"https://api.github.com/repos/olegsych/AutoFixture/merges","archive_url":"https://api.github.com/repos/olegsych/AutoFixture/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/olegsych/AutoFixture/downloads","issues_url":"https://api.github.com/repos/olegsych/AutoFixture/issues{/number}","pulls_url":"https://api.github.com/repos/olegsych/AutoFixture/pulls{/number}","milestones_url":"https://api.github.com/repos/olegsych/AutoFixture/milestones{/number}","notifications_url":"https://api.github.com/repos/olegsych/AutoFixture/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/olegsych/AutoFixture/labels{/name}","releases_url":"https://api.github.com/repos/olegsych/AutoFixture/releases{/id}","created_at":"2015-06-18T17:34:42Z","updated_at":"2015-06-18T17:34:44Z","pushed_at":"2015-08-06T01:36:05Z","git_url":"git://github.com/olegsych/AutoFixture.git","ssh_url":"git@github.com:olegsych/AutoFixture.git","clone_url":"https://github.com/olegsych/AutoFixture.git","svn_url":"https://github.com/olegsych/AutoFixture","homepage":"","size":25475,"stargazers_count":0,"watchers_count":0,"language":"C#","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"AutoFixture:master","ref":"master","sha":"8a12f2f7853d751f418d35579af8d678834b8acd","user":{"login":"AutoFixture","id":1786815,"avatar_url":"https://avatars.githubusercontent.com/u/1786815?v=3","gravatar_id":"","url":"https://api.github.com/users/AutoFixture","html_url":"https://github.com/AutoFixture","followers_url":"https://api.github.com/users/AutoFixture/followers","following_url":"https://api.github.com/users/AutoFixture/following{/other_user}","gists_url":"https://api.github.com/users/AutoFixture/gists{/gist_id}","starred_url":"https://api.github.com/users/AutoFixture/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AutoFixture/subscriptions","organizations_url":"https://api.github.com/users/AutoFixture/orgs","repos_url":"https://api.github.com/users/AutoFixture/repos","events_url":"https://api.github.com/users/AutoFixture/events{/privacy}","received_events_url":"https://api.github.com/users/AutoFixture/received_events","type":"Organization","site_admin":false},"repo":{"id":4475900,"name":"AutoFixture","full_name":"AutoFixture/AutoFixture","owner":{"login":"AutoFixture","id":1786815,"avatar_url":"https://avatars.githubusercontent.com/u/1786815?v=3","gravatar_id":"","url":"https://api.github.com/users/AutoFixture","html_url":"https://github.com/AutoFixture","followers_url":"https://api.github.com/users/AutoFixture/followers","following_url":"https://api.github.com/users/AutoFixture/following{/other_user}","gists_url":"https://api.github.com/users/AutoFixture/gists{/gist_id}","starred_url":"https://api.github.com/users/AutoFixture/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AutoFixture/subscriptions","organizations_url":"https://api.github.com/users/AutoFixture/orgs","repos_url":"https://api.github.com/users/AutoFixture/repos","events_url":"https://api.github.com/users/AutoFixture/events{/privacy}","received_events_url":"https://api.github.com/users/AutoFixture/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/AutoFixture/AutoFixture","description":"AutoFixture is an open source library for .NET designed to minimize the 'Arrange' phase of your unit tests in order to maximise maintainability.Its primary goal is to allow developers to focus on what is being tested rather than how to setup the test scenario, by making it easier to create object graphs containing test data.","fork":false,"url":"https://api.github.com/repos/AutoFixture/AutoFixture","forks_url":"https://api.github.com/repos/AutoFixture/AutoFixture/forks","keys_url":"https://api.github.com/repos/AutoFixture/AutoFixture/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AutoFixture/AutoFixture/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AutoFixture/AutoFixture/teams","hooks_url":"https://api.github.com/repos/AutoFixture/AutoFixture/hooks","issue_events_url":"https://api.github.com/repos/AutoFixture/AutoFixture/issues/events{/number}","events_url":"https://api.github.com/repos/AutoFixture/AutoFixture/events","assignees_url":"https://api.github.com/repos/AutoFixture/AutoFixture/assignees{/user}","branches_url":"https://api.github.com/repos/AutoFixture/AutoFixture/branches{/branch}","tags_url":"https://api.github.com/repos/AutoFixture/AutoFixture/tags","blobs_url":"https://api.github.com/repos/AutoFixture/AutoFixture/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AutoFixture/AutoFixture/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AutoFixture/AutoFixture/git/refs{/sha}","trees_url":"https://api.github.com/repos/AutoFixture/AutoFixture/git/trees{/sha}","statuses_url":"https://api.github.com/repos/AutoFixture/AutoFixture/statuses/{sha}","languages_url":"https://api.github.com/repos/AutoFixture/AutoFixture/languages","stargazers_url":"https://api.github.com/repos/AutoFixture/AutoFixture/stargazers","contributors_url":"https://api.github.com/repos/AutoFixture/AutoFixture/contributors","subscribers_url":"https://api.github.com/repos/AutoFixture/AutoFixture/subscribers","subscription_url":"https://api.github.com/repos/AutoFixture/AutoFixture/subscription","commits_url":"https://api.github.com/repos/AutoFixture/AutoFixture/commits{/sha}","git_commits_url":"https://api.github.com/repos/AutoFixture/AutoFixture/git/commits{/sha}","comments_url":"https://api.github.com/repos/AutoFixture/AutoFixture/comments{/number}","issue_comment_url":"https://api.github.com/repos/AutoFixture/AutoFixture/issues/comments{/number}","contents_url":"https://api.github.com/repos/AutoFixture/AutoFixture/contents/{+path}","compare_url":"https://api.github.com/repos/AutoFixture/AutoFixture/compare/{base}...{head}","merges_url":"https://api.github.com/repos/AutoFixture/AutoFixture/merges","archive_url":"https://api.github.com/repos/AutoFixture/AutoFixture/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AutoFixture/AutoFixture/downloads","issues_url":"https://api.github.com/repos/AutoFixture/AutoFixture/issues{/number}","pulls_url":"https://api.github.com/repos/AutoFixture/AutoFixture/pulls{/number}","milestones_url":"https://api.github.com/repos/AutoFixture/AutoFixture/milestones{/number}","notifications_url":"https://api.github.com/repos/AutoFixture/AutoFixture/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AutoFixture/AutoFixture/labels{/name}","releases_url":"https://api.github.com/repos/AutoFixture/AutoFixture/releases{/id}","created_at":"2012-05-29T00:00:02Z","updated_at":"2015-08-07T05:06:16Z","pushed_at":"2015-08-06T06:03:52Z","git_url":"git://github.com/AutoFixture/AutoFixture.git","ssh_url":"git@github.com:AutoFixture/AutoFixture.git","clone_url":"https://github.com/AutoFixture/AutoFixture.git","svn_url":"https://github.com/AutoFixture/AutoFixture","homepage":"","size":41136,"stargazers_count":647,"watchers_count":647,"language":"C#","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":114,"mirror_url":null,"open_issues_count":41,"forks":114,"open_issues":41,"watchers":647,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/AutoFixture/AutoFixture/pulls/430"},"html":{"href":"https://github.com/AutoFixture/AutoFixture/pull/430"},"issue":{"href":"https://api.github.com/repos/AutoFixture/AutoFixture/issues/430"},"comments":{"href":"https://api.github.com/repos/AutoFixture/AutoFixture/issues/430/comments"},"review_comments":{"href":"https://api.github.com/repos/AutoFixture/AutoFixture/pulls/430/comments"},"review_comment":{"href":"https://api.github.com/repos/AutoFixture/AutoFixture/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/AutoFixture/AutoFixture/pulls/430/commits"},"statuses":{"href":"https://api.github.com/repos/AutoFixture/AutoFixture/statuses/9809ab24fe714b71a0a0c94f6ef2c44a5c17b176"}}}}