Skip to content
Browse files

Add ability to set different uris for insert, update and delete

  • Loading branch information...
1 parent 4b5d278 commit e832ae4e83b7487ce9b5df73242afa45b8ff47c9 @nikitin-da nikitin-da committed
View
65 ...fresh/storio/common/annotations/processor/introspection/AnnotatedFieldValidationTest.java
@@ -0,0 +1,65 @@
+package com.pushtorefresh.storio.common.annotations.processor.introspection;
+
+import com.pushtorefresh.storio.common.annotations.processor.ProcessingException;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.lang.model.element.Modifier;
+
+import static javax.lang.model.element.ElementKind.METHOD;
+import static org.mockito.Mockito.when;
+
+public class AnnotatedFieldValidationTest {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Test
+ public void failIfEnclosingElementIsNotClass() {
+ AnnotationProcessorStub stub = AnnotationProcessorStub.newInstance();
+ when(stub.enclosingElement.getKind()).thenReturn(METHOD);
+
+ expectedException.expect(ProcessingException.class);
+ expectedException.expectMessage("Please apply TestClassAnnotation to fields of class: TestField");
+ stub.processor.validateAnnotatedField(stub.field);
+ }
+
+ @Test
+ public void failIfThereIsNoAnnotation() {
+ AnnotationProcessorStub stub = AnnotationProcessorStub.newInstance();
+ when(stub.enclosingElement.getAnnotation(AnnotationProcessorStub.TestClassAnnotation.class)).thenReturn(null);
+
+ expectedException.expect(ProcessingException.class);
+ expectedException.expectMessage("Please annotate class TestClass with TestClassAnnotation");
+ stub.processor.validateAnnotatedField(stub.field);
+ }
+
+ @Test
+ public void failIfFieldPrivate() {
+ AnnotationProcessorStub stub = AnnotationProcessorStub.newInstance();
+ Set<Modifier> modifiers = new HashSet<Modifier>();
+ modifiers.add(Modifier.PRIVATE);
+ when(stub.field.getModifiers()).thenReturn(modifiers);
+
+ expectedException.expect(ProcessingException.class);
+ expectedException.expectMessage("TestFieldAnnotation can not be applied to private field: TestField");
+ stub.processor.validateAnnotatedField(stub.field);
+ }
+
+ @Test
+ public void failIfFieldFinal() {
+ AnnotationProcessorStub stub = AnnotationProcessorStub.newInstance();
+ Set<Modifier> modifiers = new HashSet<Modifier>();
+ modifiers.add(Modifier.FINAL);
+ when(stub.field.getModifiers()).thenReturn(modifiers);
+
+ expectedException.expect(ProcessingException.class);
+ expectedException.expectMessage("TestFieldAnnotation can not be applied to final field: TestField");
+ stub.processor.validateAnnotatedField(stub.field);
+ }
+}
View
78 ...htorefresh/storio/common/annotations/processor/introspection/AnnotationProcessorStub.java
@@ -0,0 +1,78 @@
+package com.pushtorefresh.storio.common.annotations.processor.introspection;
+
+import com.pushtorefresh.storio.common.annotations.processor.StorIOAnnotationsProcessor;
+
+import org.jetbrains.annotations.NotNull;
+import org.mockito.Mockito;
+
+import java.lang.annotation.Annotation;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.Name;
+
+import static javax.lang.model.element.ElementKind.CLASS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class AnnotationProcessorStub {
+
+ final TestStorIOAnnotationsProcessor processor;
+ final Element field;
+ final Element enclosingElement;
+ final TestClassAnnotation classAnnotation;
+ final TestFieldAnnotation fieldAnnotation;
+
+ @NotNull
+ static AnnotationProcessorStub newInstance() {
+ return new AnnotationProcessorStub();
+ }
+
+ public AnnotationProcessorStub() {
+ processor = mock(TestStorIOAnnotationsProcessor.class, Mockito.CALLS_REAL_METHODS);
+
+ field = mock(Element.class);
+
+ Name name = mock(Name.class);
+ when(name.toString()).thenReturn("TestField");
+ when(field.getSimpleName()).thenReturn(name);
+
+ enclosingElement = mock(Element.class);
+ Name className = mock(Name.class);
+ when(className.toString()).thenReturn("TestClass");
+ when(enclosingElement.getSimpleName()).thenReturn(className);
+ when(enclosingElement.getKind()).thenReturn(CLASS);
+
+ when(field.getEnclosingElement()).thenReturn(enclosingElement);
+
+ classAnnotation = mock(TestClassAnnotation.class);
+ fieldAnnotation = mock(TestFieldAnnotation.class);
+
+ when(enclosingElement.getAnnotation(TestClassAnnotation.class)).thenReturn(classAnnotation);
+ }
+
+ protected static abstract class TestStorIOAnnotationsProcessor extends StorIOAnnotationsProcessor {
+
+ @Override
+ public void validateAnnotatedField(@NotNull Element annotatedField) {
+ super.validateAnnotatedField(annotatedField);
+ }
+
+ @NotNull
+ @Override
+ public Class<? extends Annotation> getTypeAnnotationClass() {
+ return TestClassAnnotation.class;
+ }
+
+ @NotNull
+ @Override
+ protected Class<? extends Annotation> getColumnAnnotationClass() {
+ return TestFieldAnnotation.class;
+ }
+ }
+
+ static abstract class TestClassAnnotation implements Annotation {
+ }
+
+ static abstract class TestFieldAnnotation implements Annotation {
+ }
+}
View
61 ...orefresh/storio/contentresolver/annotations/processor/StorIOContentResolverProcessor.java
@@ -14,9 +14,13 @@
import com.pushtorefresh.storio.contentresolver.annotations.processor.introspection.StorIOContentResolverTypeMeta;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -65,14 +69,14 @@
protected StorIOContentResolverTypeMeta processAnnotatedClass(@NotNull TypeElement classElement, @NotNull Elements elementUtils) {
final StorIOContentResolverType storIOContentResolverType = classElement.getAnnotation(StorIOContentResolverType.class);
- final String uri = storIOContentResolverType.uri();
+ final String commonUri = storIOContentResolverType.uri();
- if (uri == null || uri.length() == 0) {
- throw new ProcessingException(
- classElement,
- "Uri of " + classElement.getQualifiedName() + " annotated with " + StorIOContentResolverType.class.getSimpleName() + " is null or empty"
- );
- }
+ final Map<String, String> urisForOperations = new HashMap<String, String>(3);
+ urisForOperations.put("insert", storIOContentResolverType.insertUri());
+ urisForOperations.put("update", storIOContentResolverType.updateUri());
+ urisForOperations.put("delete", storIOContentResolverType.deleteUri());
+
+ validateUris(classElement, commonUri, urisForOperations);
final String simpleName = classElement.getSimpleName().toString();
final String packageName = elementUtils.getPackageOf(classElement).getQualifiedName().toString();
@@ -80,6 +84,49 @@ protected StorIOContentResolverTypeMeta processAnnotatedClass(@NotNull TypeEleme
return new StorIOContentResolverTypeMeta(simpleName, packageName, storIOContentResolverType);
}
+
+ /**
+ * Verifies that uris are valid.
+ *
+ * @param classElement type element
+ * @param commonUri nullable default uri for all operations
+ * @param operationUriMap non-null map where
+ * key - operation name,
+ * value - specific uri for this operation
+ */
+ protected void validateUris(
+ @NotNull TypeElement classElement,
+ @Nullable String commonUri,
+ @NotNull Map<String, String> operationUriMap) {
+
+ if(!validateUri(commonUri)) {
+ final List<String> operationsWithInvalidUris = new ArrayList<String>(operationUriMap.size());
+ for (Map.Entry<String, String> entry : operationUriMap.entrySet()) {
+ if (!validateUri(entry.getValue())) {
+ operationsWithInvalidUris.add(entry.getKey());
+ }
+ }
+ if (!operationsWithInvalidUris.isEmpty()) {
+ String message = "Uri of " + classElement.getQualifiedName()
+ + " annotated with " + getTypeAnnotationClass().getSimpleName() + " is null or empty";
+
+ if (operationsWithInvalidUris.size() < operationUriMap.size()) {
+ message += " for operation " + operationsWithInvalidUris.get(0);
+ }
+ // Else (there is no any uris) - do not specify operation,
+ // because commonUri is default and straightforward way.
+
+ throw new ProcessingException(classElement, message);
+ }
+
+ // It will be okay if uris for all operations were specified separately.
+ }
+ }
+
+ private boolean validateUri(@Nullable String uri) {
+ return uri != null && uri.length() > 0;
+ }
+
/**
* Processes fields annotated with {@link StorIOContentResolverColumn}
*
View
7 ...efresh/storio/contentresolver/annotations/processor/generate/DeleteResolverGenerator.java
@@ -41,6 +41,11 @@ public JavaFile generateJavaFile(@NotNull final StorIOContentResolverTypeMeta st
private MethodSpec createMapToDeleteQueryMethodSpec(@NotNull final StorIOContentResolverTypeMeta storIOContentResolverTypeMeta, @NotNull final ClassName storIOContentResolverTypeClassName) {
final Map<String, String> where = QueryGenerator.createWhere(storIOContentResolverTypeMeta, "object");
+ String deleteUri = storIOContentResolverTypeMeta.storIOType.deleteUri();
+ if (deleteUri == null || deleteUri.length() == 0) {
+ deleteUri = storIOContentResolverTypeMeta.storIOType.uri();
+ }
+
return MethodSpec.methodBuilder("mapToDeleteQuery")
.addJavadoc("{@inheritDoc}\n")
.addAnnotation(Override.class)
@@ -55,7 +60,7 @@ private MethodSpec createMapToDeleteQueryMethodSpec(@NotNull final StorIOContent
INDENT + ".where($S)\n" +
INDENT + ".whereArgs($L)\n" +
INDENT + ".build();\n",
- storIOContentResolverTypeMeta.storIOType.uri(),
+ deleteUri,
where.get(QueryGenerator.WHERE_CLAUSE),
where.get(QueryGenerator.WHERE_ARGS))
.build();
View
14 ...torefresh/storio/contentresolver/annotations/processor/generate/PutResolverGenerator.java
@@ -43,6 +43,11 @@ public JavaFile generateJavaFile(@NotNull final StorIOContentResolverTypeMeta st
@NotNull
private MethodSpec createMapToInsertQueryMethodSpec(@NotNull final StorIOContentResolverTypeMeta storIOContentResolverTypeMeta, @NotNull final ClassName storIOContentResolverClassName) {
+ String insertUri = storIOContentResolverTypeMeta.storIOType.insertUri();
+ if (insertUri == null || insertUri.length() == 0) {
+ insertUri = storIOContentResolverTypeMeta.storIOType.uri();
+ }
+
return MethodSpec.methodBuilder("mapToInsertQuery")
.addJavadoc("{@inheritDoc}\n")
.addAnnotation(Override.class)
@@ -55,7 +60,7 @@ private MethodSpec createMapToInsertQueryMethodSpec(@NotNull final StorIOContent
.addCode("return InsertQuery.builder()\n" +
INDENT + ".uri($S)\n" +
INDENT + ".build();\n",
- storIOContentResolverTypeMeta.storIOType.uri())
+ insertUri)
.build();
}
@@ -63,6 +68,11 @@ private MethodSpec createMapToInsertQueryMethodSpec(@NotNull final StorIOContent
private MethodSpec createMapToUpdateQueryMethodSpec(@NotNull final StorIOContentResolverTypeMeta storIOContentResolverTypeMeta, @NotNull final ClassName storIOContentResolverClassName) {
final Map<String, String> where = QueryGenerator.createWhere(storIOContentResolverTypeMeta, "object");
+ String updateUri = storIOContentResolverTypeMeta.storIOType.updateUri();
+ if (updateUri == null || updateUri.length() == 0) {
+ updateUri = storIOContentResolverTypeMeta.storIOType.uri();
+ }
+
return MethodSpec.methodBuilder("mapToUpdateQuery")
.addJavadoc("{@inheritDoc}\n")
.addAnnotation(Override.class)
@@ -77,7 +87,7 @@ private MethodSpec createMapToUpdateQueryMethodSpec(@NotNull final StorIOContent
INDENT + ".where($S)\n" +
INDENT + ".whereArgs($L)\n" +
INDENT + ".build();\n",
- storIOContentResolverTypeMeta.storIOType.uri(),
+ updateUri,
where.get(QueryGenerator.WHERE_CLAUSE),
where.get(QueryGenerator.WHERE_ARGS))
.build();
View
73 ...htorefresh/storio/contentresolver/annotations/processor/ContentResolverProcessorStub.java
@@ -0,0 +1,73 @@
+package com.pushtorefresh.storio.contentresolver.annotations.processor;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.mockito.Mockito;
+
+import java.lang.annotation.Annotation;
+import java.util.Map;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.TypeElement;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ContentResolverProcessorStub {
+
+ final TestStorIOContentResolverProcessor processor;
+ final TypeElement classElement;
+ final TestClassAnnotation classAnnotation;
+
+ @NotNull
+ static ContentResolverProcessorStub newInstance() {
+ return new ContentResolverProcessorStub();
+ }
+
+ public ContentResolverProcessorStub() {
+ processor = mock(TestStorIOContentResolverProcessor.class, Mockito.CALLS_REAL_METHODS);
+ classAnnotation = mock(TestClassAnnotation.class);
+
+ classElement = mock(TypeElement.class);
+ Name qualifiedName = mock(Name.class);
+ when(qualifiedName.toString()).thenReturn("ClassElementName");
+ when(classElement.getQualifiedName()).thenReturn(qualifiedName);
+ }
+
+ protected static abstract class TestStorIOContentResolverProcessor extends StorIOContentResolverProcessor {
+
+ // region Public Morozov
+ @Override
+ public void validateAnnotatedField(@NotNull Element annotatedField) {
+ super.validateAnnotatedField(annotatedField);
+ }
+
+ public void validateUris(
+ @NotNull TypeElement classElement,
+ @Nullable String commonUri,
+ @NotNull Map operationUriMap) {
+ //noinspection unchecked
+ super.validateUris(classElement, commonUri, operationUriMap);
+ }
+ // endregion
+
+ @NotNull
+ @Override
+ public Class<? extends Annotation> getTypeAnnotationClass() {
+ return TestClassAnnotation.class;
+ }
+
+ @NotNull
+ @Override
+ protected Class<? extends Annotation> getColumnAnnotationClass() {
+ return TestFieldAnnotation.class;
+ }
+ }
+
+ static abstract class TestClassAnnotation implements Annotation {
+ }
+
+ static abstract class TestFieldAnnotation implements Annotation {
+ }
+}
View
61 ...ava/com/pushtorefresh/storio/contentresolver/annotations/processor/UriValidationTest.java
@@ -0,0 +1,61 @@
+package com.pushtorefresh.storio.contentresolver.annotations.processor;
+
+import com.pushtorefresh.storio.common.annotations.processor.ProcessingException;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+public class UriValidationTest {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Test
+ public void successIfCommonNameExist() {
+ ContentResolverProcessorStub stub = ContentResolverProcessorStub.newInstance();
+ stub.processor.validateUris(stub.classElement, "content://testUri", Collections.emptyMap());
+ }
+
+ @Test
+ public void successIfNamesForOperationsExist() {
+ ContentResolverProcessorStub stub = ContentResolverProcessorStub.newInstance();
+ stub.processor.validateUris(stub.classElement, "", Collections.singletonMap("operation", "content://testUri"));
+ }
+
+ @Test
+ public void failIfNameForOperationIsEmpty() {
+ ContentResolverProcessorStub stub = ContentResolverProcessorStub.newInstance();
+
+ Map<String, String> operationNameMap = new HashMap<String, String>(3);
+ operationNameMap.put("insert", "content://insertUri");
+ operationNameMap.put("update", "");
+ operationNameMap.put("delete", "content://deleteUri");
+
+ expectedException.expect(ProcessingException.class);
+ expectedException.expectMessage("Uri of ClassElementName annotated " +
+ "with TestClassAnnotation is null or empty for operation update");
+
+ stub.processor.validateUris(stub.classElement, "", operationNameMap);
+ }
+
+ @Test
+ public void failIfAllNamesAreEmpty() {
+ ContentResolverProcessorStub stub = ContentResolverProcessorStub.newInstance();
+
+ Map<String, String> operationNameMap = new HashMap<String, String>(3);
+ operationNameMap.put("insert", "");
+ operationNameMap.put("update", "");
+ operationNameMap.put("delete", "");
+
+ expectedException.expect(ProcessingException.class);
+ expectedException.expectMessage("Uri of ClassElementName annotated " +
+ "with TestClassAnnotation is null or empty"); // Without operation marker
+
+ stub.processor.validateUris(stub.classElement, "", operationNameMap);
+ }
+}
View
124 ...sh/storio/contentresolver/annotations/processor/generate/DeleteResolverGeneratorTest.java
@@ -6,6 +6,7 @@
import com.pushtorefresh.storio.contentresolver.annotations.processor.introspection.StorIOContentResolverTypeMeta;
import com.squareup.javapoet.JavaFile;
+import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import java.io.IOException;
@@ -16,11 +17,9 @@
public class DeleteResolverGeneratorTest {
- @Test
- public void generateJavaFile() throws IOException {
- final StorIOContentResolverType storIOContentResolverType = mock(StorIOContentResolverType.class);
-
- when(storIOContentResolverType.uri()).thenReturn("content://test");
+ @NotNull
+ private String generateJavaFile(
+ @NotNull StorIOContentResolverType storIOContentResolverType) throws IOException {
final StorIOContentResolverTypeMeta storIOContentResolverTypeMeta = new StorIOContentResolverTypeMeta(
"TestItem",
@@ -58,7 +57,17 @@ public void generateJavaFile() throws IOException {
final StringBuilder out = new StringBuilder();
javaFile.writeTo(out);
- assertThat(out.toString()).isEqualTo("package com.test;\n" +
+ return out.toString();
+ }
+
+ @Test
+ public void generateJavaFileWithCommonUri() throws IOException {
+ final StorIOContentResolverType storIOContentResolverType = mock(StorIOContentResolverType.class);
+
+ when(storIOContentResolverType.uri()).thenReturn("content://test");
+
+ String javaFileAsString = generateJavaFile(storIOContentResolverType);
+ assertThat(javaFileAsString).isEqualTo("package com.test;\n" +
"\n" +
"import android.support.annotation.NonNull;\n" +
"import com.pushtorefresh.storio.contentresolver.operations.delete.DefaultDeleteResolver;\n" +
@@ -83,4 +92,107 @@ public void generateJavaFile() throws IOException {
" }\n" +
"}\n");
}
+
+ @Test
+ public void generateJavaFileWithOperationSpecificUri() throws IOException {
+ final StorIOContentResolverType storIOContentResolverType = mock(StorIOContentResolverType.class);
+
+ when(storIOContentResolverType.deleteUri()).thenReturn("content://delete_test");
+
+ String javaFileAsString = generateJavaFile(storIOContentResolverType);
+ assertThat(javaFileAsString).isEqualTo("package com.test;\n" +
+ "\n" +
+ "import android.support.annotation.NonNull;\n" +
+ "import com.pushtorefresh.storio.contentresolver.operations.delete.DefaultDeleteResolver;\n" +
+ "import com.pushtorefresh.storio.contentresolver.queries.DeleteQuery;\n" +
+ "import java.lang.Override;\n" +
+ "\n" +
+ "/**\n" +
+ " * Generated resolver for Delete Operation\n" +
+ " */\n" +
+ "public class TestItemStorIOContentResolverDeleteResolver extends DefaultDeleteResolver<TestItem> {\n" +
+ " /**\n" +
+ " * {@inheritDoc}\n" +
+ " */\n" +
+ " @Override\n" +
+ " @NonNull\n" +
+ " protected DeleteQuery mapToDeleteQuery(@NonNull TestItem object) {\n" +
+ " return DeleteQuery.builder()\n" +
+ " .uri(\"content://delete_test\")\n" + // Operation specific
+ " .where(null)\n" +
+ " .whereArgs(null)\n" +
+ " .build();\n" +
+ " }\n" +
+ "}\n");
+ }
+
+ @Test
+ public void operationSpecificUriShouldHaveHigherPriority() throws IOException {
+ final StorIOContentResolverType storIOContentResolverType = mock(StorIOContentResolverType.class);
+
+ when(storIOContentResolverType.uri()).thenReturn("content://test");
+ when(storIOContentResolverType.deleteUri()).thenReturn("content://delete_test");
+
+ String javaFileAsString = generateJavaFile(storIOContentResolverType);
+ assertThat(javaFileAsString).isEqualTo("package com.test;\n" +
+ "\n" +
+ "import android.support.annotation.NonNull;\n" +
+ "import com.pushtorefresh.storio.contentresolver.operations.delete.DefaultDeleteResolver;\n" +
+ "import com.pushtorefresh.storio.contentresolver.queries.DeleteQuery;\n" +
+ "import java.lang.Override;\n" +
+ "\n" +
+ "/**\n" +
+ " * Generated resolver for Delete Operation\n" +
+ " */\n" +
+ "public class TestItemStorIOContentResolverDeleteResolver extends DefaultDeleteResolver<TestItem> {\n" +
+ " /**\n" +
+ " * {@inheritDoc}\n" +
+ " */\n" +
+ " @Override\n" +
+ " @NonNull\n" +
+ " protected DeleteQuery mapToDeleteQuery(@NonNull TestItem object) {\n" +
+ " return DeleteQuery.builder()\n" +
+ " .uri(\"content://delete_test\")\n" + // Operation specific
+ " .where(null)\n" +
+ " .whereArgs(null)\n" +
+ " .build();\n" +
+ " }\n" +
+ "}\n");
+ }
+
+ @Test
+ public void shouldUseCommonUriIfSpecifiedOnlyForAnotherOperations() throws IOException {
+ final StorIOContentResolverType storIOContentResolverType = mock(StorIOContentResolverType.class);
+
+ when(storIOContentResolverType.uri()).thenReturn("content://test");
+ when(storIOContentResolverType.insertUri()).thenReturn("content://insert_test");
+ when(storIOContentResolverType.updateUri()).thenReturn("content://update_test");
+ // There is no explicit uri for delete operation
+
+ String javaFileAsString = generateJavaFile(storIOContentResolverType);
+ assertThat(javaFileAsString).isEqualTo("package com.test;\n" +
+ "\n" +
+ "import android.support.annotation.NonNull;\n" +
+ "import com.pushtorefresh.storio.contentresolver.operations.delete.DefaultDeleteResolver;\n" +
+ "import com.pushtorefresh.storio.contentresolver.queries.DeleteQuery;\n" +
+ "import java.lang.Override;\n" +
+ "\n" +
+ "/**\n" +
+ " * Generated resolver for Delete Operation\n" +
+ " */\n" +
+ "public class TestItemStorIOContentResolverDeleteResolver extends DefaultDeleteResolver<TestItem> {\n" +
+ " /**\n" +
+ " * {@inheritDoc}\n" +
+ " */\n" +
+ " @Override\n" +
+ " @NonNull\n" +
+ " protected DeleteQuery mapToDeleteQuery(@NonNull TestItem object) {\n" +
+ " return DeleteQuery.builder()\n" +
+ " .uri(\"content://test\")\n" + // Common uri
+ " .where(null)\n" +
+ " .whereArgs(null)\n" +
+ " .build();\n" +
+ " }\n" +
+ "}\n");
+ }
}
View
206 ...fresh/storio/contentresolver/annotations/processor/generate/PutResolverGeneratorTest.java
@@ -6,6 +6,7 @@
import com.pushtorefresh.storio.contentresolver.annotations.processor.introspection.StorIOContentResolverTypeMeta;
import com.squareup.javapoet.JavaFile;
+import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import java.io.IOException;
@@ -17,14 +18,10 @@
public class PutResolverGeneratorTest {
@SuppressWarnings("ConstantConditions")
- @Test
- public void generateJavaFile() throws IOException {
+ @NotNull
+ private String generateJavaFile(@NotNull StorIOContentResolverType storIOContentResolverType) throws IOException {
final PutResolverGenerator putResolverGenerator = new PutResolverGenerator();
- final StorIOContentResolverType storIOContentResolverType = mock(StorIOContentResolverType.class);
-
- when(storIOContentResolverType.uri()).thenReturn("content://test");
-
final StorIOContentResolverTypeMeta storIOContentResolverTypeMeta = new StorIOContentResolverTypeMeta("TestItem", "com.test", storIOContentResolverType);
final StorIOContentResolverColumn storIOContentResolverColumn1 = mock(StorIOContentResolverColumn.class);
@@ -55,7 +52,17 @@ public void generateJavaFile() throws IOException {
final StringBuilder out = new StringBuilder();
javaFile.writeTo(out);
- assertThat(out.toString()).isEqualTo("package com.test;\n" +
+ return out.toString();
+ }
+
+ @Test
+ public void generateJavaFileWithCommonUri() throws IOException {
+ final StorIOContentResolverType storIOContentResolverType = mock(StorIOContentResolverType.class);
+
+ when(storIOContentResolverType.uri()).thenReturn("content://test");
+
+ String javaFileAsString = generateJavaFile(storIOContentResolverType);
+ assertThat(javaFileAsString).isEqualTo("package com.test;\n" +
"\n" +
"import android.content.ContentValues;\n" +
"import android.support.annotation.NonNull;\n" +
@@ -107,4 +114,189 @@ public void generateJavaFile() throws IOException {
" }\n" +
"}\n");
}
+
+ @Test
+ public void generateJavaFileWithOperationSpecificUri() throws IOException {
+ final StorIOContentResolverType storIOContentResolverType = mock(StorIOContentResolverType.class);
+
+ when(storIOContentResolverType.insertUri()).thenReturn("content://insert_test");
+ when(storIOContentResolverType.updateUri()).thenReturn("content://update_test");
+
+ String javaFileAsString = generateJavaFile(storIOContentResolverType);
+ assertThat(javaFileAsString).isEqualTo("package com.test;\n" +
+ "\n" +
+ "import android.content.ContentValues;\n" +
+ "import android.support.annotation.NonNull;\n" +
+ "import com.pushtorefresh.storio.contentresolver.operations.put.DefaultPutResolver;\n" +
+ "import com.pushtorefresh.storio.contentresolver.queries.InsertQuery;\n" +
+ "import com.pushtorefresh.storio.contentresolver.queries.UpdateQuery;\n" +
+ "import java.lang.Override;\n" +
+ "\n" +
+ "/**\n" +
+ " * Generated resolver for Put Operation\n" +
+ " */\n" +
+ "public class TestItemStorIOContentResolverPutResolver extends DefaultPutResolver<TestItem> {\n" +
+ " /**\n" +
+ " * {@inheritDoc}\n" +
+ " */\n" +
+ " @Override\n" +
+ " @NonNull\n" +
+ " protected InsertQuery mapToInsertQuery(@NonNull TestItem object) {\n" +
+ " return InsertQuery.builder()\n" +
+ " .uri(\"content://insert_test\")\n" + // Operation specific
+ " .build();\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * {@inheritDoc}\n" +
+ " */\n" +
+ " @Override\n" +
+ " @NonNull\n" +
+ " protected UpdateQuery mapToUpdateQuery(@NonNull TestItem object) {\n" +
+ " return UpdateQuery.builder()\n" +
+ " .uri(\"content://update_test\")\n" + // Operation specific
+ " .where(\"column1 = ?\")\n" +
+ " .whereArgs(object.column1Field)\n" +
+ " .build();\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * {@inheritDoc}\n" +
+ " */\n" +
+ " @Override\n" +
+ " @NonNull\n" +
+ " public ContentValues mapToContentValues(@NonNull TestItem object) {\n" +
+ " ContentValues contentValues = new ContentValues(2);\n" +
+ "\n" +
+ " contentValues.put(\"column1\", object.column1Field);\n" +
+ " contentValues.put(\"column2\", object.column2Field);\n" +
+ "\n" +
+ " return contentValues;\n" +
+ " }\n" +
+ "}\n");
+ }
+
+ @Test
+ public void operationSpecificUriShouldHaveHigherPriority() throws IOException {
+ final StorIOContentResolverType storIOContentResolverType = mock(StorIOContentResolverType.class);
+
+ when(storIOContentResolverType.uri()).thenReturn("content://test");
+ when(storIOContentResolverType.insertUri()).thenReturn("content://insert_test");
+ when(storIOContentResolverType.updateUri()).thenReturn("content://update_test");
+
+ String javaFileAsString = generateJavaFile(storIOContentResolverType);
+ assertThat(javaFileAsString).isEqualTo("package com.test;\n" +
+ "\n" +
+ "import android.content.ContentValues;\n" +
+ "import android.support.annotation.NonNull;\n" +
+ "import com.pushtorefresh.storio.contentresolver.operations.put.DefaultPutResolver;\n" +
+ "import com.pushtorefresh.storio.contentresolver.queries.InsertQuery;\n" +
+ "import com.pushtorefresh.storio.contentresolver.queries.UpdateQuery;\n" +
+ "import java.lang.Override;\n" +
+ "\n" +
+ "/**\n" +
+ " * Generated resolver for Put Operation\n" +
+ " */\n" +
+ "public class TestItemStorIOContentResolverPutResolver extends DefaultPutResolver<TestItem> {\n" +
+ " /**\n" +
+ " * {@inheritDoc}\n" +
+ " */\n" +
+ " @Override\n" +
+ " @NonNull\n" +
+ " protected InsertQuery mapToInsertQuery(@NonNull TestItem object) {\n" +
+ " return InsertQuery.builder()\n" +
+ " .uri(\"content://insert_test\")\n" + // Operation specific
+ " .build();\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * {@inheritDoc}\n" +
+ " */\n" +
+ " @Override\n" +
+ " @NonNull\n" +
+ " protected UpdateQuery mapToUpdateQuery(@NonNull TestItem object) {\n" +
+ " return UpdateQuery.builder()\n" +
+ " .uri(\"content://update_test\")\n" + // Operation specific
+ " .where(\"column1 = ?\")\n" +
+ " .whereArgs(object.column1Field)\n" +
+ " .build();\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * {@inheritDoc}\n" +
+ " */\n" +
+ " @Override\n" +
+ " @NonNull\n" +
+ " public ContentValues mapToContentValues(@NonNull TestItem object) {\n" +
+ " ContentValues contentValues = new ContentValues(2);\n" +
+ "\n" +
+ " contentValues.put(\"column1\", object.column1Field);\n" +
+ " contentValues.put(\"column2\", object.column2Field);\n" +
+ "\n" +
+ " return contentValues;\n" +
+ " }\n" +
+ "}\n");
+ }
+
+ @Test
+ public void shouldUseCommonUriIfSpecifiedOnlyForAnotherOperations() throws IOException {
+ final StorIOContentResolverType storIOContentResolverType = mock(StorIOContentResolverType.class);
+
+ when(storIOContentResolverType.uri()).thenReturn("content://test");
+ when(storIOContentResolverType.deleteUri()).thenReturn("content://delete_test");
+ // There is no explicit uri for insert and update operations
+
+ String javaFileAsString = generateJavaFile(storIOContentResolverType);
+ assertThat(javaFileAsString).isEqualTo("package com.test;\n" +
+ "\n" +
+ "import android.content.ContentValues;\n" +
+ "import android.support.annotation.NonNull;\n" +
+ "import com.pushtorefresh.storio.contentresolver.operations.put.DefaultPutResolver;\n" +
+ "import com.pushtorefresh.storio.contentresolver.queries.InsertQuery;\n" +
+ "import com.pushtorefresh.storio.contentresolver.queries.UpdateQuery;\n" +
+ "import java.lang.Override;\n" +
+ "\n" +
+ "/**\n" +
+ " * Generated resolver for Put Operation\n" +
+ " */\n" +
+ "public class TestItemStorIOContentResolverPutResolver extends DefaultPutResolver<TestItem> {\n" +
+ " /**\n" +
+ " * {@inheritDoc}\n" +
+ " */\n" +
+ " @Override\n" +
+ " @NonNull\n" +
+ " protected InsertQuery mapToInsertQuery(@NonNull TestItem object) {\n" +
+ " return InsertQuery.builder()\n" +
+ " .uri(\"content://test\")\n" + // Common uri
+ " .build();\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * {@inheritDoc}\n" +
+ " */\n" +
+ " @Override\n" +
+ " @NonNull\n" +
+ " protected UpdateQuery mapToUpdateQuery(@NonNull TestItem object) {\n" +
+ " return UpdateQuery.builder()\n" +
+ " .uri(\"content://test\")\n" + // Common uri
+ " .where(\"column1 = ?\")\n" +
+ " .whereArgs(object.column1Field)\n" +
+ " .build();\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * {@inheritDoc}\n" +
+ " */\n" +
+ " @Override\n" +
+ " @NonNull\n" +
+ " public ContentValues mapToContentValues(@NonNull TestItem object) {\n" +
+ " ContentValues contentValues = new ContentValues(2);\n" +
+ "\n" +
+ " contentValues.put(\"column1\", object.column1Field);\n" +
+ " contentValues.put(\"column2\", object.column2Field);\n" +
+ "\n" +
+ " return contentValues;\n" +
+ " }\n" +
+ "}\n");
+ }
}
View
29 .../java/com/pushtorefresh/storio/contentresolver/annotations/StorIOContentResolverType.java
@@ -14,9 +14,34 @@
public @interface StorIOContentResolverType {
/**
- * Required: Specifies uri
+ * Optional: Specifies uri for all operations
+ * Should be set as default if there is no uri for some particular operation
*
* @return uri
+ * @see #insertUri()
+ * @see #updateUri()
+ * @see #deleteUri()
*/
- String uri();
+ String uri() default "";
+
+ /**
+ * Optional: Specifies uri for insert operation
+ *
+ * @return uri
+ */
+ String insertUri() default "";
+
+ /**
+ * Optional: Specifies uri for update operation
+ *
+ * @return uri
+ */
+ String updateUri() default "";
+
+ /**
+ * Optional: Specifies uri for delete operation
+ *
+ * @return uri
+ */
+ String deleteUri() default "";
}

0 comments on commit e832ae4

Please sign in to comment.
Something went wrong with that request. Please try again.