@Test public void testGoodConcreteTypes() throws Exception { analyzeProcessElementMethod( new AnonymousMethod() { private void method(DoFn<Integer, String>.ProcessContext c) {} }); }
@Test public void testNewTrackerWrongNumArguments() throws Exception { thrown.expectMessage("Must have a single argument"); DoFnSignatures.analyzeNewTrackerMethod( errors(), TypeDescriptor.of(FakeDoFn.class), new AnonymousMethod() { private SomeRestrictionTracker method(SomeRestriction restriction, Object extra) { return null; } }.getMethod()); }
@Test public void testNewTrackerInconsistent() throws Exception { thrown.expectMessage( "Returns SomeRestrictionTracker, " + "but must return a subtype of RestrictionTracker<String, ?>"); DoFnSignatures.analyzeNewTrackerMethod( errors(), TypeDescriptor.of(FakeDoFn.class), new AnonymousMethod() { private SomeRestrictionTracker method(String restriction) { return null; } }.getMethod()); } }
@Test public void testBadReturnType() throws Exception { thrown.expect(IllegalArgumentException.class); thrown.expectMessage("Must return void or ProcessContinuation"); analyzeProcessElementMethod( new AnonymousMethod() { private int method(DoFn<Integer, String>.ProcessContext context) { return 0; } }); }
static DoFnSignature.ProcessElementMethod analyzeProcessElementMethod(AnonymousMethod method) throws Exception { return DoFnSignatures.analyzeProcessElementMethod( errors(), TypeDescriptor.of(FakeDoFn.class), method.getMethod(), TypeDescriptor.of(Integer.class), TypeDescriptor.of(String.class), FnAnalysisContext.create()); } }
@Test public void testReturnsProcessContinuation() throws Exception { DoFnSignature.ProcessElementMethod signature = analyzeProcessElementMethod( new AnonymousMethod() { private DoFn.ProcessContinuation method( DoFn<Integer, String>.ProcessContext context) { return null; } }); assertTrue(signature.hasReturnValue()); }
@Test public void testSplitRestrictionWrongNumArguments() throws Exception { thrown.expectMessage("Must have exactly 3 arguments"); DoFnSignatures.analyzeSplitRestrictionMethod( errors(), TypeDescriptor.of(FakeDoFn.class), new AnonymousMethod() { private void method( Integer element, SomeRestriction restriction, DoFn.OutputReceiver<SomeRestriction> receiver, Object extra) {} }.getMethod(), TypeDescriptor.of(Integer.class)); }
@Test public void testBadExtraProcessContextType() throws Exception { thrown.expect(IllegalArgumentException.class); thrown.expectMessage( "Integer is not a valid context parameter. " + "Should be one of [BoundedWindow, RestrictionTracker<?, ?>]"); analyzeProcessElementMethod( new AnonymousMethod() { private void method(DoFn<Integer, String>.ProcessContext c, Integer n) {} }); }
@Test public void testSplitRestrictionReturnsWrongType() throws Exception { thrown.expectMessage( "Third argument must be DoFn.OutputReceiver<SomeRestriction>, " + "but is DoFn.OutputReceiver<String>"); DoFnSignatures.analyzeSplitRestrictionMethod( errors(), TypeDescriptor.of(FakeDoFn.class), new AnonymousMethod() { void method( Integer element, SomeRestriction restriction, DoFn.OutputReceiver<String> receiver) {} }.getMethod(), TypeDescriptor.of(Integer.class)); }
@Test public void testSplittableProcessElementMustNotHaveOtherParams() throws Exception { thrown.expect(IllegalArgumentException.class); thrown.expectMessage("Illegal parameter"); thrown.expectMessage("BoundedWindow"); DoFnSignature.ProcessElementMethod signature = analyzeProcessElementMethod( new AnonymousMethod() { private void method( DoFn<Integer, String>.ProcessContext context, SomeRestrictionTracker tracker, BoundedWindow window) {} }); }
@Test public void testSplitRestrictionWrongElementArgument() throws Exception { class BadFn { private List<SomeRestriction> splitRestriction(String element, SomeRestriction restriction) { return null; } } thrown.expectMessage("First argument must be the element type Integer"); DoFnSignatures.analyzeSplitRestrictionMethod( errors(), TypeDescriptor.of(FakeDoFn.class), new AnonymousMethod() { void method( String element, SomeRestriction restriction, DoFn.OutputReceiver<SomeRestriction> receiver) {} }.getMethod(), TypeDescriptor.of(Integer.class)); }
@Test public void testBadGenericsTwoArgs() throws Exception { thrown.expect(IllegalArgumentException.class); thrown.expectMessage("DoFn<Integer, Integer>.ProcessContext"); thrown.expectMessage("must have type"); thrown.expectMessage("DoFn<Integer, String>.ProcessContext"); analyzeProcessElementMethod( new AnonymousMethod() { private void method(DoFn<Integer, Integer>.ProcessContext c) {} }); }
@Test public void testBadExtraContext() throws Exception { thrown.expect(IllegalArgumentException.class); thrown.expectMessage( "Must take a single argument of type DoFn<Integer, String>.StartBundleContext"); DoFnSignatures.analyzeStartBundleMethod( errors(), TypeDescriptor.of(FakeDoFn.class), new DoFnSignaturesTestUtils.AnonymousMethod() { void method(DoFn<Integer, String>.StartBundleContext c, int n) {} }.getMethod(), TypeDescriptor.of(Integer.class), TypeDescriptor.of(String.class)); }
@Test public void testBadGenericWildCards() throws Exception { thrown.expect(IllegalArgumentException.class); thrown.expectMessage("DoFn<Integer, ? super Integer>.ProcessContext"); thrown.expectMessage("must have type"); thrown.expectMessage("DoFn<Integer, String>.ProcessContext"); analyzeProcessElementMethod( new AnonymousMethod() { private void method(DoFn<Integer, ? super Integer>.ProcessContext c) {} }); }
@Test public void testHasRestrictionTracker() throws Exception { DoFnSignature.ProcessElementMethod signature = analyzeProcessElementMethod( new AnonymousMethod() { private void method( DoFn<Integer, String>.ProcessContext context, SomeRestrictionTracker tracker) {} }); assertTrue(signature.isSplittable()); assertTrue( signature .extraParameters() .stream() .anyMatch( Predicates.instanceOf(DoFnSignature.Parameter.RestrictionTrackerParameter.class) ::apply)); assertEquals(SomeRestrictionTracker.class, signature.trackerT().getRawType()); }