{"action":"created","issue":{"url":"https://api.github.com/repos/mockito/mockito/issues/194","labels_url":"https://api.github.com/repos/mockito/mockito/issues/194/labels{/name}","comments_url":"https://api.github.com/repos/mockito/mockito/issues/194/comments","events_url":"https://api.github.com/repos/mockito/mockito/issues/194/events","html_url":"https://github.com/mockito/mockito/issues/194","id":66425003,"number":194,"title":"Tweaks Matchers.any family matchers behavior","user":{"login":"bric3","id":803621,"avatar_url":"https://avatars.githubusercontent.com/u/803621?v=3","gravatar_id":"","url":"https://api.github.com/users/bric3","html_url":"https://github.com/bric3","followers_url":"https://api.github.com/users/bric3/followers","following_url":"https://api.github.com/users/bric3/following{/other_user}","gists_url":"https://api.github.com/users/bric3/gists{/gist_id}","starred_url":"https://api.github.com/users/bric3/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bric3/subscriptions","organizations_url":"https://api.github.com/users/bric3/orgs","repos_url":"https://api.github.com/users/bric3/repos","events_url":"https://api.github.com/users/bric3/events{/privacy}","received_events_url":"https://api.github.com/users/bric3/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/mockito/mockito/labels/refactoring","name":"refactoring","color":"c7def8"}],"state":"open","locked":false,"assignee":null,"milestone":{"url":"https://api.github.com/repos/mockito/mockito/milestones/1","html_url":"https://github.com/mockito/mockito/milestones/2.0","labels_url":"https://api.github.com/repos/mockito/mockito/milestones/1/labels","id":945543,"number":1,"title":"2.0","description":null,"creator":{"login":"bric3","id":803621,"avatar_url":"https://avatars.githubusercontent.com/u/803621?v=3","gravatar_id":"","url":"https://api.github.com/users/bric3","html_url":"https://github.com/bric3","followers_url":"https://api.github.com/users/bric3/followers","following_url":"https://api.github.com/users/bric3/following{/other_user}","gists_url":"https://api.github.com/users/bric3/gists{/gist_id}","starred_url":"https://api.github.com/users/bric3/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bric3/subscriptions","organizations_url":"https://api.github.com/users/bric3/orgs","repos_url":"https://api.github.com/users/bric3/repos","events_url":"https://api.github.com/users/bric3/events{/privacy}","received_events_url":"https://api.github.com/users/bric3/received_events","type":"User","site_admin":false},"open_issues":4,"closed_issues":0,"state":"open","created_at":"2015-01-21T16:53:47Z","updated_at":"2015-04-05T10:23:55Z","due_on":null,"closed_at":null},"comments":9,"created_at":"2015-04-05T10:23:55Z","updated_at":"2015-04-08T12:01:24Z","closed_at":null,"body":"This issue is a follow up of the work started in #141 by @pimterry. Also here's an extract of a message on [this thread](https://groups.google.com/forum/#!topic/mockito/8_WGBB3Jbtk) of the mailing list :\r\n\r\n-------------\r\n\r\nThe origin of these methods is they come from `anything` i.e. anything matches, later for shortness and cast avoidance the aliases grew, but the API naming thus became inconsistent with what a human would expect. So this behavior is being changed in mockito 2 beta, to be precise here's the status on these API in the version 2.0.5-beta :\r\n\r\n- `any`, `anyObject`, `any(Class)` won't check anything (at first they were just aliases for _anything_ and for cast avoidance)\r\n- `anyX` like `anyString` will check the arg is not null and that has the correct type\r\n- `anyList` will check the argument is not null and a `List` instance\r\n- `anyListOf` (and the likes) at the moment are just aliases to their non generic counter part like `anyList`\r\n\r\nNote this is work in progress (started here in [#141](https://github.com/mockito/mockito/pull/141)), these new behavior can / will change in the beta phase. I'm especially wondering if the `any` family should allow `null` and if not do a type check. For example with these matchers : \r\n\r\n- `any`, `anyObject` stay the same, they currently allow `null` and don't have to do type check anyway\r\n- `any(Class)` currently allows `null` and doesn't do type check => allows `null` and if not checks for the given type\r\n- `any<Collection>Of` currently doesn't allow `null` and does a type check of the collection, not elements => allows `null`, if not checks collection type, if not empty checks element type\r\n\r\nMaybe extend/create a _symmetric_  `isA` family API that won't allow any `null` arguments.\r\n\r\n-------------\r\n\r\n"},"comment":{"url":"https://api.github.com/repos/mockito/mockito/issues/comments/90892185","html_url":"https://github.com/mockito/mockito/issues/194#issuecomment-90892185","issue_url":"https://api.github.com/repos/mockito/mockito/issues/194","id":90892185,"user":{"login":"folarte","id":9819771,"avatar_url":"https://avatars.githubusercontent.com/u/9819771?v=3","gravatar_id":"","url":"https://api.github.com/users/folarte","html_url":"https://github.com/folarte","followers_url":"https://api.github.com/users/folarte/followers","following_url":"https://api.github.com/users/folarte/following{/other_user}","gists_url":"https://api.github.com/users/folarte/gists{/gist_id}","starred_url":"https://api.github.com/users/folarte/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/folarte/subscriptions","organizations_url":"https://api.github.com/users/folarte/orgs","repos_url":"https://api.github.com/users/folarte/repos","events_url":"https://api.github.com/users/folarte/events{/privacy}","received_events_url":"https://api.github.com/users/folarte/received_events","type":"User","site_admin":false},"created_at":"2015-04-08T12:01:24Z","updated_at":"2015-04-08T12:01:24Z","body":"Hi Tim:\n\nOn Tue, Apr 7, 2015 at 7:37 PM, Tim Perry <notifications@github.com> wrote:\n> The issue with getting rid of anyAs(X.class) is that we want two things:\n>\n> A way to match an argument without checking anything about its value (any)\n> A way to match an argument and check its type (isA)\n>\n> I think your solution is to just use any() with no parameter everywhere to cover the first case, and specify the type when you want the 2nd case. That won't work, because target type inference doesn't work for method arguments in Java < 8, so it's impossible to use any() without an argument (unless the parameter is just Object typed).\n\nI don't think you've understood my solution. From the previously\npropossed one ( any() + anyAs(Class) + isA(Class) + isNullOrA(class) (\n+ notNull(), which is in another place ) I propose to remove anyAs,\ngiven it does not check type, rename isA(Class) to anyNotNull(Class),\nrename isNullOrA(Class) to any(Class) and rename ( or forward )\nnotNull() to anyNotNull().\n\n\n>\n> Specifically, in Java 7 the below won't compile:\n>\n> class X {\n>    public bool method(List l) { ... }\n> }\n>\n> X x = mock(X.class);\n>\n> // ERROR: method(java.collections.List) cannot be applied to (java.lang.Object)\n> when (x.method(any()).thenReturn(true);\n\nPerfect, in this case you use the propossed isNullOrA(Class), which I\nproposed to rename as any(Class).\n\nAlso, just grepped and got this from one of my test files:\n\n        AC1 = mock(AutoCaller.class);\n        when(AC1.makeCall((AcCallRequest) any())).thenReturn(resp1);\n\nIn case you wonder, AutoCaller is an interface with a method\n\"MakeCallResponse makeCall(AcCallRequest)\", not overloaded.\n\nI think this is clearly superior in java 7 ( I'm unable to use java 8\non those projects due to problems with the app server ). The any()\nconveys the 'i do not care, just make this compile' and the cast\nclearly says 'this is due to one of those java 7 shortcomings' to me.\n\n\n> Anybody on Java < 8 has to specify the type every time they match anything, or it's impossible to make it compile. They can never really use any(); they always have to use any(X.class) (or equivalent). We need a way in Java 7 that you can say 'match absolutely anything please' that compiles, and I think any(X.class) or equivalent is the only option.\n\nWhich is what I proposed, you have IsNullOrA(Class), which covers\nthis. Correct me if wrong.\n\n> If you make that any(X.class) matcher check the type (as you suggest) then it no longer matches everything any more, and it becomes impossible to wildcard match everything in Java < 8 (without casting, but that would be pretty nasty)\n\nIt is. The Method has a declared argument type of List, which means\nthe compiler will check that when you use the mock, in\nx.method(whatever) whatever implements List, so isNullOrA(List.class),\nor any(List.class) will allways match whatever, with an extra\nredundant type check.\n\n\n> Therefore if you want to be able to both match specific types and wildcard 'match everything' in Java < 8, you have to have two separate APIs to do so. The names of those APIs need to clearly tell the user which of those two things they're doing ('match anything, but cast the matcher to make it compile' vs 'match only this type').\n\nAs I said, I'm not knowdledgeable enough and haven't got time\npresently to dig through the sources. If any(List.class) matches when\nI pass an ArrayList to the Mock I can always wildcard by using the\ndeclared argument type.\n\n> I don't think that's avoidable. I'm very happy to take better suggestions for anyAs(X.class) that make it clearer it's just a convenient casting method (without making it so nasty that it stops being convenient), but that method does still need to exist I think.\n\nForget about my proposed renaming., With the any/anyAs/isA/IsNullOrA\nproposal, is there any case in which you must use anyAs() which cannot\nbe solved by using isNullOrA(X.class)? I think they are synonims. The\nproblem I see with anyAs as stated is that, in the previous example (\nwithout overloads ), I could code a matcher as\nwhen(x.method(anyAs(ArrayList.class))) and it shoud fire ( as it does\nnot check type ) when I do x.method(new LinkedList()). I think this is\nconfusing and asking for problem, and by making it check the type I\ncould make when(x.method(anyAss(ArrayList.class))) to catch one\nspecific thing and after that add when(x.method(anyAs(List.class)) for\na catch all in java<8, or just plain any() in >=8.\n\nMy proposal of getting rid of anyAs can be read the other way, make\nanyAs() check type and get rid of isNullOrA.\n\nRepeating my self, I proposed to get rid of anyAs(Class) as a I feel\nit seems to match something which it does not, and it cannot do\nanything which cannot be done with isNullOr(class). Name it whatever,\nis the functionality with worries me.\n\n> In addition to all that: we'd rather the 'match a specific type' matcher didn't accept nulls by default (as your any(List.class) does). We need to make people opt in to matching nulls, because it's good practice, and because there's some potentially confusing behaviour there as nulls are kind of outside the type system. We also can't have the wildcard matcher reject nulls, or it's not matching everything any more. Thus, again, they need to be two different methods.\n\nThat's another thing. What I propose is to simplify so I have two\nnames ( anyIncludingNull, anyNotNull ) which indicate wether null is\naccepted, plus two overrides, no parameters and a class parameter. The\nnull accepting behaviour is functionaly equivalent to haven just a\nname plus a boolean parameter ( notReallyAny(boolean acceptNull) +\nnotReallyAny(boolean acceptNull, Class klass) ).\n\nWhat makes me feel uncorfortable with the proposal is :\n\n- Too many names, I think two suffice.\n- Different names for similar methods, similar names for different\nnull accepting behaviour.\n\nGiven this, I think:\n\n- anyIncludingNul(), anyIncludingNul(Class), anyNotNull(),\nanyNotNul(Class) cover all cases, for jdk <8 & 8 ( although\nparameterless ones are not too useful in <8 ) ( your example would be\nserved by when(x.method(anyIncludingNull(List.class)) ).\n\n- names should be kept paired. You state opting in for nulls is good\npractice, I'll accept that without discussion. You say people should\nopt in to use them, I accept thas as a precondition. Writing\nanyIncludingNull is for me opting in.\n\nBut then, we want 'any()'. It's nice, sounds good, it is short, reads\ngood (any() in 8, I do not care, just need this to compile,\nany(List.class) in 7, I do not care, but .Well, then writing 'any(' is\nopting in to use nulls, so the class version should begin with 'any('\ntoo. I have no problem with having the null accepting versions\n'nonDefaultAcceptingNullsAnyMatcher', and the other one 'any', or\n'isA', IDEs are really good at completing, and I can easily manage a\ncouple of names, but having any, anyAs, isA, isNullOrA, and notNull\nhorrifies me.\n\nWell, that's all for today. I hope it clarifies my position.\n\nRegards.\n    Francisco Olarte.\n"}}