1 package org.robolectric.annotation.processing.validator; 2 3 import static com.google.common.truth.Fact.simpleFact; 4 import static com.google.common.truth.Truth.assertAbout; 5 import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources; 6 import static org.robolectric.annotation.processing.Utils.DEFAULT_OPTS; 7 8 import com.google.common.collect.ImmutableList; 9 import com.google.common.truth.FailureMetadata; 10 import com.google.common.truth.Subject; 11 import com.google.testing.compile.CompileTester; 12 import com.google.testing.compile.CompileTester.LineClause; 13 import com.google.testing.compile.CompileTester.SuccessfulCompilationClause; 14 import com.google.testing.compile.CompileTester.UnsuccessfulCompilationClause; 15 import com.google.testing.compile.JavaFileObjects; 16 import java.util.HashMap; 17 import java.util.Map; 18 import javax.tools.JavaFileObject; 19 import org.robolectric.annotation.processing.RobolectricProcessor; 20 import org.robolectric.annotation.processing.Utils; 21 22 public final class SingleClassSubject extends Subject { 23 singleClass()24 public static Subject.Factory<SingleClassSubject, String> singleClass() { 25 return SingleClassSubject::new; 26 } 27 singleClass( Map<String, String> processorOpts, String sdkLocation, int sdkInt)28 public static Subject.Factory<SingleClassSubject, String> singleClass( 29 Map<String, String> processorOpts, String sdkLocation, int sdkInt) { 30 return (FailureMetadata failureMetadata, String subject) -> 31 new SingleClassSubject(failureMetadata, subject, processorOpts, sdkLocation, sdkInt); 32 } 33 singleClass( Map<String, String> processorOpts)34 public static Subject.Factory<SingleClassSubject, String> singleClass( 35 Map<String, String> processorOpts) { 36 return (FailureMetadata failureMetadata, String subject) -> 37 new SingleClassSubject(failureMetadata, subject, processorOpts); 38 } 39 40 JavaFileObject source; 41 CompileTester tester; 42 SingleClassSubject(FailureMetadata failureMetadata, String subject)43 public SingleClassSubject(FailureMetadata failureMetadata, String subject) { 44 this(failureMetadata, subject, DEFAULT_OPTS); 45 } 46 SingleClassSubject( FailureMetadata failureMetadata, String subject, Map<String, String> processorOpts)47 public SingleClassSubject( 48 FailureMetadata failureMetadata, String subject, Map<String, String> processorOpts) { 49 this(failureMetadata, subject, processorOpts, null, -1); 50 } 51 SingleClassSubject( FailureMetadata failureMetadata, String subject, Map<String, String> processorOpts, String sdkLocation, int sdkInt)52 public SingleClassSubject( 53 FailureMetadata failureMetadata, 54 String subject, 55 Map<String, String> processorOpts, 56 String sdkLocation, 57 int sdkInt) { 58 super(failureMetadata, subject); 59 source = JavaFileObjects.forResource(Utils.toResourcePath(subject)); 60 Map<String, String> opts = new HashMap<>(DEFAULT_OPTS); 61 opts.putAll(processorOpts); 62 tester = 63 assertAbout(javaSources()) 64 .that(ImmutableList.of(source, Utils.SHADOW_EXTRACTOR_SOURCE)) 65 .processedWith(new RobolectricProcessor(opts, sdkLocation, sdkInt)); 66 } 67 compilesWithoutError()68 public SuccessfulCompilationClause compilesWithoutError() { 69 try { 70 return tester.compilesWithoutError(); 71 } catch (AssertionError e) { 72 failWithoutActual(simpleFact(e.getMessage())); 73 } 74 return null; 75 } 76 failsToCompile()77 public SingleFileClause failsToCompile() { 78 try { 79 return new SingleFileClause(tester.failsToCompile(), source); 80 } catch (AssertionError e) { 81 failWithoutActual(simpleFact(e.getMessage())); 82 } 83 return null; 84 } 85 86 final class SingleFileClause implements CompileTester.ChainingClause<SingleFileClause> { 87 88 UnsuccessfulCompilationClause unsuccessful; 89 JavaFileObject source; 90 SingleFileClause(UnsuccessfulCompilationClause unsuccessful, JavaFileObject source)91 public SingleFileClause(UnsuccessfulCompilationClause unsuccessful, JavaFileObject source) { 92 this.unsuccessful = unsuccessful; 93 this.source = source; 94 } 95 withErrorContaining(final String messageFragment)96 public SingleLineClause withErrorContaining(final String messageFragment) { 97 try { 98 return new SingleLineClause(unsuccessful.withErrorContaining(messageFragment).in(source)); 99 } catch (AssertionError e) { 100 failWithoutActual(simpleFact(e.getMessage())); 101 } 102 return null; 103 } 104 withNoErrorContaining(final String messageFragment)105 public SingleFileClause withNoErrorContaining(final String messageFragment) { 106 try { 107 unsuccessful.withErrorContaining(messageFragment); 108 } catch (AssertionError e) { 109 return this; 110 } 111 failWithoutActual( 112 simpleFact( 113 "Shouldn't have found any errors containing " + messageFragment + ", but we did")); 114 115 return this; 116 } 117 118 @Override and()119 public SingleFileClause and() { 120 return this; 121 } 122 123 final class SingleLineClause implements CompileTester.ChainingClause<SingleFileClause> { 124 125 LineClause lineClause; 126 SingleLineClause(LineClause lineClause)127 public SingleLineClause(LineClause lineClause) { 128 this.lineClause = lineClause; 129 } 130 onLine(long lineNumber)131 public CompileTester.ChainingClause<SingleFileClause> onLine(long lineNumber) { 132 try { 133 lineClause.onLine(lineNumber); 134 return new CompileTester.ChainingClause<SingleFileClause>() { 135 @Override 136 public SingleFileClause and() { 137 return SingleFileClause.this; 138 } 139 }; 140 } catch (AssertionError e) { 141 failWithoutActual(simpleFact(e.getMessage())); 142 } 143 return null; 144 } 145 146 @Override and()147 public SingleFileClause and() { 148 return SingleFileClause.this; 149 } 150 } 151 } 152 } 153