mirror of
https://github.com/hmalik144/Android-Cucumber-BDD-Sample.git
synced 2026-03-18 15:35:56 +00:00
Initial commit
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
package com.codemate.booklibrary;
|
||||
|
||||
import android.support.test.espresso.NoMatchingViewException;
|
||||
import android.support.test.espresso.ViewAssertion;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Created by ironman on 02/09/16.
|
||||
*/
|
||||
public class RecyclerViewAssertions {
|
||||
|
||||
public static ViewAssertion adapterItemCountEquals(int count) {
|
||||
return new ItemCountAssertion(ItemCountAssertion.MODE_EQUALS, count);
|
||||
}
|
||||
|
||||
public static ViewAssertion adapterItemCountLowerThan(int count) {
|
||||
return new ItemCountAssertion(ItemCountAssertion.MODE_LESS_THAN, count);
|
||||
}
|
||||
|
||||
private static class ItemCountAssertion implements ViewAssertion {
|
||||
private static final int MODE_EQUALS = 0;
|
||||
private static final int MODE_LESS_THAN = 1;
|
||||
|
||||
private final int mode;
|
||||
private final int expectedChildCount;
|
||||
|
||||
ItemCountAssertion(int mode, int exptectedChildCount) {
|
||||
this.mode = mode;
|
||||
this.expectedChildCount = exptectedChildCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void check (View view, NoMatchingViewException noViewFoundException) {
|
||||
if (noViewFoundException != null) {
|
||||
throw noViewFoundException;
|
||||
}
|
||||
|
||||
RecyclerView recyclerView = (RecyclerView) view;
|
||||
RecyclerView.Adapter adapter = recyclerView.getAdapter();
|
||||
|
||||
if (mode == MODE_EQUALS) {
|
||||
assertThat(expectedChildCount, is(adapter.getItemCount()));
|
||||
} else if (mode == MODE_LESS_THAN) {
|
||||
assertTrue(expectedChildCount > adapter.getItemCount());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.codemate.booklibrary.ui;
|
||||
|
||||
import android.support.test.espresso.action.ViewActions;
|
||||
import android.support.test.espresso.matcher.ViewMatchers;
|
||||
import android.support.test.rule.ActivityTestRule;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.widget.EditText;
|
||||
|
||||
import com.codemate.booklibrary.R;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static android.support.test.espresso.Espresso.onView;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static com.codemate.booklibrary.RecyclerViewAssertions.adapterItemCountEquals;
|
||||
import static com.codemate.booklibrary.RecyclerViewAssertions.adapterItemCountLowerThan;
|
||||
|
||||
/**
|
||||
* Created by ironman on 02/09/16.
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class MainActivityTest {
|
||||
@Rule
|
||||
public ActivityTestRule<MainActivity> mainActivityTestRule =
|
||||
new ActivityTestRule<>(MainActivity.class);
|
||||
|
||||
@Test
|
||||
public void allBooksDisplayedInUI() {
|
||||
onView(ViewMatchers.withId(R.id.bookRecycler))
|
||||
.check(adapterItemCountEquals(45));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onSearchTermEntered_NonMatchingItemsNotShown() {
|
||||
onView(isAssignableFrom(EditText.class))
|
||||
.perform(ViewActions.typeText("2"));
|
||||
onView(withId(R.id.bookRecycler))
|
||||
.check(adapterItemCountLowerThan(45));
|
||||
}
|
||||
}
|
||||
20
app/src/main/AndroidManifest.xml
Normal file
20
app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.codemate.booklibrary">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity android:name=".ui.MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
30
app/src/main/java/com/codemate/booklibrary/data/Book.java
Normal file
30
app/src/main/java/com/codemate/booklibrary/data/Book.java
Normal file
@@ -0,0 +1,30 @@
|
||||
package com.codemate.booklibrary.data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Created by ironman on 01/09/16.
|
||||
*/
|
||||
public class Book {
|
||||
private final String title;
|
||||
private final String author;
|
||||
private final Date publishDate;
|
||||
|
||||
public Book(String title, String author, Date publishDate) {
|
||||
this.title = title;
|
||||
this.author = author;
|
||||
this.publishDate = publishDate;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public Date getPublishDate() {
|
||||
return publishDate;
|
||||
}
|
||||
}
|
||||
95
app/src/main/java/com/codemate/booklibrary/data/Library.java
Normal file
95
app/src/main/java/com/codemate/booklibrary/data/Library.java
Normal file
@@ -0,0 +1,95 @@
|
||||
package com.codemate.booklibrary.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by ironman on 01/09/16.
|
||||
*/
|
||||
public class Library {
|
||||
private List<Book> inventory = new ArrayList<>();
|
||||
|
||||
public void addBook(Book book) {
|
||||
inventory.add(book);
|
||||
}
|
||||
|
||||
public void addBooks(List<Book> books) {
|
||||
inventory.addAll(books);
|
||||
}
|
||||
|
||||
public List<Book> getAllBooks() {
|
||||
return inventory;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a stupid search. In a real scenario, we would have something that
|
||||
* would be much better.
|
||||
*/
|
||||
public List<Book> search(String searchQuery) {
|
||||
List<Book> results = new ArrayList<>();
|
||||
|
||||
if (searchQuery.matches("^[1-9][0-9]{0,3}$")) {
|
||||
results.addAll(findBooksByYear(searchQuery));
|
||||
}
|
||||
|
||||
results.addAll(findBooksByAuthor(searchQuery));
|
||||
results.addAll(findBooksByTitle(searchQuery));
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public List<Book> findBooksByAuthor(String authorQuery) {
|
||||
List<Book> results = new ArrayList<>();
|
||||
|
||||
for (Book candidate : inventory) {
|
||||
String normalizedAuthor = candidate.getAuthor().toLowerCase();
|
||||
String normalizedSearchQuery = authorQuery.toLowerCase();
|
||||
|
||||
if (normalizedAuthor.contains(normalizedSearchQuery)) {
|
||||
results.add(candidate);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public List<Book> findBooksByTitle(String titleQuery) {
|
||||
List<Book> results = new ArrayList<>();
|
||||
|
||||
for (Book candidate : inventory) {
|
||||
String normalizedTitle = candidate.getTitle().toLowerCase();
|
||||
String normalizedSearchQuery = titleQuery.toLowerCase();
|
||||
|
||||
if (normalizedTitle.contains(normalizedSearchQuery)) {
|
||||
results.add(candidate);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public List<Book> findBooksByYear(String searchedYear) {
|
||||
List<Book> results = new ArrayList<>();
|
||||
|
||||
for (Book candidate : inventory) {
|
||||
Calendar candidateCalendar = Calendar.getInstance();
|
||||
candidateCalendar.setTime(candidate.getPublishDate());
|
||||
|
||||
int candidateYear = candidateCalendar.get(Calendar.YEAR);
|
||||
|
||||
if (candidateYear == Integer.valueOf(searchedYear)
|
||||
|| yearsStartSimilarly(candidateYear, searchedYear)) {
|
||||
results.add(candidate);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private boolean yearsStartSimilarly(int candidateYear, String searchedYear) {
|
||||
String candidate = String.valueOf(candidateYear);
|
||||
|
||||
return candidate.startsWith(searchedYear);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.codemate.booklibrary.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by ironman on 02/09/16.
|
||||
*/
|
||||
public class RandomBookGenerator {
|
||||
private RandomBookGenerator() {}
|
||||
|
||||
private static final String[] SUBJECTS = {
|
||||
"Chicken", "Pig", "Hippo", "Dinosaur", "Giraffe", "Orangutan",
|
||||
"Bat", "Lion", "Daddy", "Grandpa", "Donald Trump", "Coffee",
|
||||
"Dog", "Rat", "Pokemon", "Cat", "Senile", "Pensioner",
|
||||
"Project manager", "Salesperson"
|
||||
};
|
||||
|
||||
private static final String[] SECOND_WORDS = {
|
||||
"strip club", "that knew too little", "Strategy", "parking space",
|
||||
"Office", "Banana", "Toilet", "Poop", "Fart", "Rain", "Job",
|
||||
"Thing", "Radio", "Zoo", "Office", "House", "Village",
|
||||
"swimming pool", "Computer"
|
||||
};
|
||||
|
||||
private static final String[] FIRST_NAMES = {
|
||||
"Bob", "Anna", "Tim", "Bethany", "Donald", "Mickey", "John",
|
||||
"George", "Dick", "James", "Timothy", "Joanne", "Angus"
|
||||
};
|
||||
|
||||
private static final String[] LAST_NAMES = {
|
||||
"Doe", "Trump", "Bond", "Jackson", "Jordan", "Young", "Page",
|
||||
"Johnson", "Springsteen", "Kauffman", "Schmidt", "Jokinen"
|
||||
};
|
||||
|
||||
public static List<Book> randomBooks(int howMany) {
|
||||
List<Book> books = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < howMany; i++) {
|
||||
books.add(randomBook());
|
||||
}
|
||||
|
||||
return books;
|
||||
}
|
||||
|
||||
public static Book randomBook() {
|
||||
String title = randomTitle();
|
||||
String author = randomAuthor();
|
||||
Date date = randomDate();
|
||||
|
||||
return new Book(title, author, date);
|
||||
}
|
||||
|
||||
private static String randomTitle() {
|
||||
String subject = RandomUtils.randomFromArray(SUBJECTS);
|
||||
String secondWord = RandomUtils.randomFromArray(SECOND_WORDS);
|
||||
|
||||
return subject + " " + secondWord;
|
||||
}
|
||||
|
||||
private static String randomAuthor() {
|
||||
String firstName = RandomUtils.randomFromArray(FIRST_NAMES);
|
||||
String lastName = RandomUtils.randomFromArray(LAST_NAMES);
|
||||
|
||||
return firstName + " " + lastName;
|
||||
}
|
||||
|
||||
private static Date randomDate() {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.set(Calendar.YEAR, RandomUtils.randBetween(1995, 2016));
|
||||
calendar.set(Calendar.MONTH, RandomUtils.randBetween(0, 11));
|
||||
calendar.set(Calendar.DAY_OF_MONTH, RandomUtils.randBetween(1, 25));
|
||||
|
||||
return calendar.getTime();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.codemate.booklibrary.data;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Created by ironman on 02/09/16.
|
||||
*/
|
||||
public class RandomUtils {
|
||||
private RandomUtils() {}
|
||||
|
||||
private static final Random random;
|
||||
|
||||
static {
|
||||
random = new Random();
|
||||
}
|
||||
|
||||
public static <T> T randomFromArray(T[] array) {
|
||||
return array[randBetween(0, array.length - 1)];
|
||||
}
|
||||
|
||||
public static int randBetween(int start, int end) {
|
||||
return start + (int) Math.round(random.nextDouble() * (end - start));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.codemate.booklibrary.ui;
|
||||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.codemate.booklibrary.data.Book;
|
||||
import com.codemate.booklibrary.R;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Created by ironman on 02/09/16.
|
||||
*/
|
||||
public class BookAdapter extends RecyclerView.Adapter<BookAdapter.ViewHolder> {
|
||||
private final SimpleDateFormat dateFormat;
|
||||
private List<Book> items = new ArrayList<>();
|
||||
|
||||
public BookAdapter() {
|
||||
dateFormat = new SimpleDateFormat("yyyy", Locale.getDefault());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
||||
View itemView = inflater.inflate(R.layout.item_book, parent, false);
|
||||
|
||||
return new ViewHolder(itemView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
Book book = items.get(position);
|
||||
|
||||
holder.title.setText(book.getTitle());
|
||||
holder.author.setText(book.getAuthor());
|
||||
holder.date.setText(dateFormat.format(book.getPublishDate()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return items.size();
|
||||
}
|
||||
|
||||
public void updateItems(List<Book> books) {
|
||||
this.items = books;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder {
|
||||
final TextView title;
|
||||
final TextView author;
|
||||
final TextView date;
|
||||
|
||||
public ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
||||
title = (TextView) itemView.findViewById(R.id.bookTitle);
|
||||
author = (TextView) itemView.findViewById(R.id.bookAuthor);
|
||||
date = (TextView) itemView.findViewById(R.id.bookDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.codemate.booklibrary.ui;
|
||||
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.SearchView;
|
||||
|
||||
import com.codemate.booklibrary.data.Book;
|
||||
import com.codemate.booklibrary.data.Library;
|
||||
import com.codemate.booklibrary.R;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MainActivity extends AppCompatActivity implements MainView, SearchView.OnQueryTextListener {
|
||||
|
||||
private MainPresenter presenter;
|
||||
private BookAdapter bookAdapter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
initializeViews();
|
||||
|
||||
presenter = new MainPresenter(this, new Library());
|
||||
presenter.loadAllBooks();
|
||||
}
|
||||
|
||||
private void initializeViews() {
|
||||
bookAdapter = new BookAdapter();
|
||||
|
||||
RecyclerView bookRecycler = (RecyclerView) findViewById(R.id.bookRecycler);
|
||||
bookRecycler.setLayoutManager(new LinearLayoutManager(this));
|
||||
bookRecycler.setAdapter(bookAdapter);
|
||||
|
||||
SearchView searchView = (SearchView) findViewById(R.id.searchView);
|
||||
searchView.setOnQueryTextListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(String query) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(String newText) {
|
||||
presenter.searchForBooks(newText);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showBooks(List<Book> books) {
|
||||
bookAdapter.updateItems(books);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.codemate.booklibrary.ui;
|
||||
|
||||
import com.codemate.booklibrary.data.Book;
|
||||
import com.codemate.booklibrary.data.Library;
|
||||
import com.codemate.booklibrary.data.RandomBookGenerator;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by ironman on 02/09/16.
|
||||
*/
|
||||
public class MainPresenter {
|
||||
private final MainView mainView;
|
||||
private final Library library;
|
||||
|
||||
public MainPresenter(MainView mainView, Library library) {
|
||||
this.mainView = mainView;
|
||||
this.library = library;
|
||||
}
|
||||
|
||||
public void searchForBooks(String searchQuery) {
|
||||
List<Book> searchResults = library.search(searchQuery);
|
||||
loadBooks(searchResults);
|
||||
}
|
||||
|
||||
public void loadAllBooks() {
|
||||
// Populate the library with fake dummy data. In a real app
|
||||
// we would have an interactor that would fetch the books from
|
||||
// a real API.
|
||||
List<Book> books = RandomBookGenerator.randomBooks(45);
|
||||
library.addBooks(books);
|
||||
|
||||
loadBooks(library.getAllBooks());
|
||||
}
|
||||
|
||||
public void loadBooks(List<Book> books) {
|
||||
mainView.showBooks(books);
|
||||
}
|
||||
}
|
||||
12
app/src/main/java/com/codemate/booklibrary/ui/MainView.java
Normal file
12
app/src/main/java/com/codemate/booklibrary/ui/MainView.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package com.codemate.booklibrary.ui;
|
||||
|
||||
import com.codemate.booklibrary.data.Book;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by ironman on 02/09/16.
|
||||
*/
|
||||
public interface MainView {
|
||||
void showBooks(List<Book> books);
|
||||
}
|
||||
27
app/src/main/res/layout/activity_main.xml
Normal file
27
app/src/main/res/layout/activity_main.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
tools:context=".ui.MainActivity">
|
||||
|
||||
<android.support.v7.widget.SearchView
|
||||
android:id="@+id/searchView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
app:iconifiedByDefault="false"
|
||||
app:queryHint="Search by title, author or year..." />
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/bookRecycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingRight="8dp"
|
||||
android:clipToPadding="false"
|
||||
android:layout_below="@id/searchView"
|
||||
android:scrollbars="vertical"/>
|
||||
|
||||
</RelativeLayout>
|
||||
30
app/src/main/res/layout/item_book.xml
Normal file
30
app/src/main/res/layout/item_book.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bookTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Title"
|
||||
tools:text="Book Title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bookAuthor"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
|
||||
tools:text="Book Author" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bookDate"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Caption"
|
||||
tools:text="2016" />
|
||||
|
||||
</LinearLayout>
|
||||
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.7 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
6
app/src/main/res/values-w820dp/dimens.xml
Normal file
6
app/src/main/res/values-w820dp/dimens.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<resources>
|
||||
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
|
||||
(such as screen margins) for screens with more than 820dp of available width. This
|
||||
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
|
||||
<dimen name="activity_horizontal_margin">64dp</dimen>
|
||||
</resources>
|
||||
6
app/src/main/res/values/colors.xml
Normal file
6
app/src/main/res/values/colors.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#3F51B5</color>
|
||||
<color name="colorPrimaryDark">#303F9F</color>
|
||||
<color name="colorAccent">#FF4081</color>
|
||||
</resources>
|
||||
5
app/src/main/res/values/dimens.xml
Normal file
5
app/src/main/res/values/dimens.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<resources>
|
||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||
</resources>
|
||||
3
app/src/main/res/values/strings.xml
Normal file
3
app/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">Book Library</string>
|
||||
</resources>
|
||||
11
app/src/main/res/values/styles.xml
Normal file
11
app/src/main/res/values/styles.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.codemate.booklibrary;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import cucumber.api.CucumberOptions;
|
||||
import cucumber.api.junit.Cucumber;
|
||||
|
||||
/**
|
||||
* Created by ironman on 01/09/16.
|
||||
*/
|
||||
@RunWith(Cucumber.class)
|
||||
@CucumberOptions(features = "src/test/resources")
|
||||
public class CucumberTests extends TestCase {
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.codemate.booklibrary.data;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by ironman on 02/09/16.
|
||||
*/
|
||||
public class LibraryTest {
|
||||
@Test
|
||||
public void addMultipleBooks_PersistsThemInLibrary() {
|
||||
List<Book> books = RandomBookGenerator.randomBooks(3);
|
||||
Library library = new Library();
|
||||
library.addBooks(books);
|
||||
|
||||
Assert.assertEquals(books, library.getAllBooks());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.codemate.booklibrary.data;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* Created by ironman on 02/09/16.
|
||||
*/
|
||||
public class RandomBookGeneratorTest {
|
||||
@Test
|
||||
public void generatingRandomBooks_ReturnsNonEmptyBookList() {
|
||||
List<Book> books = RandomBookGenerator.randomBooks(15);
|
||||
|
||||
assertEquals(15, books.size());
|
||||
|
||||
for (Book book : books) {
|
||||
assertNotNull(book.getTitle());
|
||||
assertNotNull(book.getAuthor());
|
||||
assertNotEquals(0, book.getPublishDate().getTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.codemate.booklibrary.steps;
|
||||
|
||||
import com.codemate.booklibrary.data.Book;
|
||||
import com.codemate.booklibrary.data.Library;
|
||||
import com.codemate.booklibrary.ui.MainPresenter;
|
||||
import com.codemate.booklibrary.ui.MainView;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import cucumber.api.Format;
|
||||
import cucumber.api.PendingException;
|
||||
import cucumber.api.java.en.And;
|
||||
import cucumber.api.java.en.Given;
|
||||
import cucumber.api.java.en.Then;
|
||||
import cucumber.api.java.en.When;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Created by ironman on 01/09/16.
|
||||
*/
|
||||
public class BookSearchSteps {
|
||||
private Library library = new Library();
|
||||
private List<Book> results = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Test data populations
|
||||
*/
|
||||
@Given(".*a book with title \"([^\"]*)\", written by \"([^\"]*)\", published in (.+)$")
|
||||
public void addNewBook(String title, String author, @Format("dd MMMM yyyy") Date publishDate) throws Throwable {
|
||||
Book book = new Book(title, author, publishDate);
|
||||
library.addBook(book);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use cases
|
||||
*/
|
||||
@When("^the customer wants to know all books in the library$")
|
||||
public void getAllBooks() throws Throwable {
|
||||
results = library.getAllBooks();
|
||||
}
|
||||
|
||||
@When("^the customer searches for books by author \"([^\"]*)\"$")
|
||||
public void searchByAuthor(String authorQuery) throws Throwable {
|
||||
results = library.search(authorQuery);
|
||||
}
|
||||
|
||||
@When("^the customer searches for books with title \"([^\"]*)\"$")
|
||||
public void searchByTitle(String title) throws Throwable {
|
||||
results = library.search(title);
|
||||
}
|
||||
|
||||
@When("^the customer searches for books published in year (.*)$")
|
||||
public void searchByYear(String year) throws Throwable {
|
||||
results = library.search(year);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assertions
|
||||
*/
|
||||
@Then("^(\\d+) books should be found$")
|
||||
public void verifyAmountOfBooksFound(int booksFound) throws Throwable {
|
||||
assertEquals(booksFound, results.size());
|
||||
}
|
||||
|
||||
@And("^Book (\\d+) should have the title \"([^\"]*)\"$")
|
||||
public void verifyBookAtPosition(int position, String title) throws Throwable {
|
||||
int realPosition = position - 1;
|
||||
Assert.assertEquals(title, results.get(realPosition).getTitle());
|
||||
}
|
||||
|
||||
@And("^Books should be (.+)$")
|
||||
public void verifyBookTitlesEqualTo(String titles) throws Throwable {
|
||||
for (Book result : results) {
|
||||
assertThat(titles, containsString(result.getTitle()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.codemate.booklibrary.ui;
|
||||
|
||||
import com.codemate.booklibrary.data.Book;
|
||||
import com.codemate.booklibrary.data.Library;
|
||||
import com.codemate.booklibrary.data.RandomBookGenerator;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Created by ironman on 02/09/16.
|
||||
*/
|
||||
public class MainPresenterTest {
|
||||
|
||||
@Mock
|
||||
private MainView mainView;
|
||||
|
||||
@Mock
|
||||
private Library library;
|
||||
|
||||
private MainPresenter presenter;
|
||||
private List<Book> randomBooks;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
presenter = new MainPresenter(mainView, library);
|
||||
randomBooks = RandomBookGenerator.randomBooks(5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchForBooks_ShowsThemInUI() {
|
||||
when(library.search(anyString()))
|
||||
.thenReturn(randomBooks);
|
||||
presenter.searchForBooks("test_search");
|
||||
|
||||
verify(mainView).showBooks(randomBooks);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadAllBooks_ShowsThemInUI() {
|
||||
when(library.getAllBooks())
|
||||
.thenReturn(randomBooks);
|
||||
presenter.loadAllBooks();
|
||||
|
||||
verify(mainView).showBooks(randomBooks);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
Feature: Book Search
|
||||
A customer must be able to search books by year, author or title
|
||||
|
||||
Background:
|
||||
Given the library has a book with title "How to be awesome", written by "Iiro Krankka", published in 16 May 2016
|
||||
And a book with title "My life as an awesome guy", written by "Iiro Krankka", published in 27 July 2016
|
||||
And a book with title "I think my teacher is an asshat", written by "John Doe", published in 01 January 2010
|
||||
|
||||
Scenario: List all books
|
||||
When the customer wants to know all books in the library
|
||||
Then 3 books should be found
|
||||
And Book 1 should have the title "How to be awesome"
|
||||
And Book 2 should have the title "My life as an awesome guy"
|
||||
And Book 3 should have the title "I think my teacher is an asshat"
|
||||
|
||||
Scenario: Search books by year
|
||||
When the customer searches for books published in year 2016
|
||||
Then 2 books should be found
|
||||
And Book 1 should have the title "How to be awesome"
|
||||
And Book 2 should have the title "My life as an awesome guy"
|
||||
|
||||
Scenario Outline: Search books by author
|
||||
When the customer searches for books by author <author>
|
||||
Then 2 books should be found
|
||||
And Book 1 should have the title "How to be awesome"
|
||||
And Book 2 should have the title "My life as an awesome guy"
|
||||
|
||||
Examples:
|
||||
| author |
|
||||
| "Iiro" |
|
||||
| "Krankka" |
|
||||
| "Iiro Krankka" |
|
||||
|
||||
Scenario Outline: Search books by title
|
||||
When the customer searches for books with title <searched_title>
|
||||
Then <search_results_count> books should be found
|
||||
And Books should be <search_results>
|
||||
|
||||
Examples:
|
||||
| searched_title | search_results_count | search_results |
|
||||
| "Awesome" | 2 | "How to be awesome" and "My life as an awesome guy" |
|
||||
| "asshat" | 1 | "I think my teacher is an asshat" |
|
||||
| "How to be" | 1 | "How to be awesome" |
|
||||
Reference in New Issue
Block a user