package com.github.ryanbrainard.richsobjects.api;

import com.github.ryanbrainard.richsobjects.RichSObject;
import com.github.ryanbrainard.richsobjects.api.client.SfdcRestApiClientLoader;
import com.github.ryanbrainard.richsobjects.api.model.BasicSObjectDescription;
import com.github.ryanbrainard.richsobjects.api.model.SObjectDescription;
import com.github.ryanbrainard.richsobjects.service.RichSObjectsService;
import com.github.ryanbrainard.richsobjects.service.RichSObjectsServiceImpl;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Ryan Brainard
 */
public abstract class AbstractRichSObjectServiceTest {

    private RichSObjectsService service;
    
    @BeforeClass
    public void setupService() {
        service = new RichSObjectsServiceImpl();
        System.out.println("Running " + this.getClass() + " with API provider: " + SfdcRestApiClientLoader.get().getClass());
    }

    @Test
    public void testListSObjectTypes() {
        List<BasicSObjectDescription> basicSObjectDescriptions = service.listSObjectTypes();
        assertCollectionContains(basicSObjectDescriptions, "Account", new ElementMatcher<BasicSObjectDescription, String>() {
            @Override
            public boolean matches(BasicSObjectDescription basicSObjectDescription, String matches) {
                return basicSObjectDescription.getName().equals(matches);
            }
        });
    }

    @Test
    public void testDescribeSObject() {
        SObjectDescription rso = service.describeSObjectType("Account");
        Assert.assertEquals(rso.getName(), "Account");
    }

    @Test
    public void testSObjectCRUD() {
        Map<String, String> rawAcct = new HashMap<String, String>(1);
        rawAcct.put("Name", "TEST1");

        String acctId = service.createSObject("Account", rawAcct);
        final RichSObject acct1 = service.getSObject("Account", acctId);
        Assert.assertEquals(acct1.get("Name").getValue(), "TEST1");

        rawAcct.put("Name", "TEST2");
        service.updateSObject("Account", acctId, rawAcct);
        final RichSObject acct2 = service.getSObject("Account", acctId);
        Assert.assertEquals(acct2.get("Name").getValue(), "TEST2");

        service.deleteSObject("Account", acctId);
    }

    private static interface ElementMatcher<E,M> {
        boolean matches(E element, M matches);
    }

    private <E,M> void assertCollectionContains(List<E> collection, M matches, ElementMatcher<E,M> elementMatcher) {
        for (E element : collection) {
            if (elementMatcher.matches(element, matches)) return;
        }
        Assert.fail("Element [" + matches + "] not found in collection: \n" + collection);
    }
}

@@ -616,16 +616,43 @@
 ashMap;%0A
+import java.util.Iterator;%0A
 import j
@@ -1602,16 +1602,20 @@
 eSObject
+Type
 () %7B%0A   
@@ -1638,19 +1638,27 @@
 ription 
-rso
+description
  = servi
@@ -1724,11 +1724,19 @@
 als(
-rso
+description
 .get
@@ -1755,26 +1755,262 @@
 ount%22);%0A    
-%7D%0A
+    Assert.assertNotNull(description.getFields());%0A    %7D%0A%0A    @Test%0A    public void testGetRecentItems() %7B%0A        Iterator%3CRichSObject%3E recents = service.getRecentItems(%22Account%22);%0A        Assert.assertTrue(recents.hasNext());%0A    %7D%0A    
 %0A    @Test%0A 
@@ -2755,32 +2755,400 @@
 atches);%0A    %7D%0A%0A
+    private %3CE,M%3E void assertIteratorContains(Iterator%3CE%3E iterator, M matches, ElementMatcher%3CE,M%3E elementMatcher) %7B%0A        while(iterator.hasNext()) %7B%0A            E element = iterator.next();%0A            if (elementMatcher.matches(element, matches)) return;%0A        %7D%0A        Assert.fail(%22Element %5B%22 + matches + %22%5D not found in iterator: %5Cn%22 + iterator);%0A    %7D%0A    %0A
     private %3CE,M

Add testGetRecentItems(), which force-api currently does not support