You need to sign in to do that
Don't have an account?
help with test coverage
http://wiki.developerforce.com/page/Sorting_Tables - this is some code developed by someone else - I found it online - I made very few changes and cannot get more that 61% coverage (with this or original) - it is failing at lines 17,18,21,22,23,42,43,46,47,49,50,52,74,75,77,78
I am not sure what to add to the tests in order to get the coverage up:
public class superSort {
/*This method takes 3 arguments, the List of objects to sort, the field to sort,
and the order, asc or desc*/
public static void sortList(List<sObject> items, String sortField, String order){
/*I must give credit where it is due as the sorting algorithm I am using is the
one supplied by Andrew Waite here: http://blog.sforce.com/sforce/2008/09/sorting-collect.html */
Boolean isSortFieldReference = false;
Map<Id,String> referenceName;
/*Determine the type of the field that needs to be sorted, if it is a
reference we will want sort by the name of the related object, not the
ID itself*/
if(items[0].getSObjectType().getDescribe().fields.getMap().get(sortField).getDescribe().getType().Name() == 'REFERENCE'){
isSortFieldReference = true;
referenceName = new Map<Id,String>();
/*Determine the type of this object and populate the Id to Name map*/
Set<Id> referenceIds = new Set<Id>();
for(sObject s : items){
referenceIds.add((Id)s.get(sortField));
}
// DevAngel - EDIT - Because you may not have a value for the reference field in the first record
// in the table you are sorting, this approach will fail on the substring method. Below is
// is a more reliable method using describe calls
/*
String objectID = (String)items[0].get(sortField);
String prefix = objectID.substring(0,3);
String objectType;
Map<String, Schema.SObjectType> gd = Schema.getGlobalDescribe();
for(Schema.SObjectType s : gd.values()){
if(prefix == s.getDescribe().getKeyPrefix()){
objectType = s.getDescribe().Name;
}
}
*/
// DevAngel - EDIT - New approach...
List<Schema.Sobjecttype> objType = items[0].getSObjectType().getDescribe().fields.getMap().get(sortField).getDescribe().getReferenceTo();
String objectType = objType[0].getDescribe().getName();
//Query the related objects for the name and populate the Id -> Name map
String queryString = 'select Id, Name from ' + objectType + ' where ID IN :referenceIDs';
for(sObject s : Database.query(queryString )){
// DevAngel - EDIT - if the reference field is null then we will not have a result, so we need to "create one"
if (s.get('Name') == null) {
referenceName.put((Id)s.get('Id'), 'n/a');
} else {
referenceName.put((Id)s.get('Id'),(String)s.get('Name'));
}
}
}
/*Declare a list that will contain the sorted results. I think this is one of the
coolest parts of this method as the system will not let you declare a list of
sObjects (List<sObject> objects = new List<sObjects>();) but using a
wrapper class you can bypass this system limitation to create this type of list */
List<cObject> resultList = new List<cObject>();
//Create a map that can be used for sorting
Map<object, List<cObject>> objectMap = new Map<object, List<cObject>>();
for(sObject ob : items){
if(isSortFieldReference == false){
if(objectMap.get(ob.get(sortField)) == null){
objectMap.put(ob.get(sortField), new List<cObject>());
}
cObject o = new cObject(ob);
objectMap.get(ob.get(sortField)).add(o);
}else{
if(objectMap.get(referenceName.get((Id)ob.get(sortField))) == null){
objectMap.put(referenceName.get((Id)ob.get(sortField)), new List<cObject>());
}
cObject o = new cObject(ob);
objectMap.get(referenceName.get((Id)ob.get(sortField))).add(o);
}
}
//Sort the keys
List<object> keys = new List<object>(objectMap.keySet());
keys.sort();
for(object key : keys){
resultList.addAll(objectMap.get(key));
}
//Apply the sorted values to the source list
items.clear();
if(order.toLowerCase() == 'asc'){
for(cObject ob : resultList){
items.add(ob.obj);
}
}else if(order.toLowerCase() == 'desc'){
for(integer i = resultList.size()-1; i >= 0; i--){
items.add(resultList[i].obj);
}
}
}
public class cObject{
sObject obj {get; set;}
public cObject(sObject obj){
this.obj = obj;
}
}
/*Some test methods that provide 100% coverage */
public static testMethod void sortAscendingTest(){
List<Account> accs = new List<Account>();
for(integer i = 0; i<1000; i++){
accs.add(new Account(Name = 'test' + i, Annualized_Revenue__c = 1000 * Math.random()));
}
Test.startTest();
Long start = system.currentTimeMillis();
sortList(accs,'Annualized_Revenue__c','asc');
system.debug(system.currentTimeMillis() - start);
Test.stopTest();
//Assert the list was sorted correctly
Decimal assertValue = -1;
for(Account a : accs) {
System.debug('Acc value: ' + a.Annualized_Revenue__c);
System.assert(assertValue <= a.Annualized_Revenue__c);
assertValue = a.Annualized_Revenue__c;
}
}
public static testMethod void sortDescendingTest(){
List<Account> accs = new List<Account>();
for(integer i = 0; i<1000; i++){
accs.add(new Account(Name = 'test' + i, Annualized_Revenue__c = 1000 * Math.random()));
}
Test.startTest();
sortList(accs,'Annualized_Revenue__c','desc');
Test.stopTest();
//Assert the list was sorted correctly
Decimal assertValue = 1001;
for(Account a : accs) {
System.debug('Opp value: ' + a.Annualized_Revenue__c);
System.assert(assertValue >= a.Annualized_Revenue__c);
assertValue = a.Annualized_Revenue__c;
}
}
}
Here is what I finally worked out:
public with sharing class tableSort
{
List<Account> accs;
public String sortField {get; set;}
public String previousSortField {get; set;}
public List<Account> getaccs()
{
if(accs == null){
accs = [select Id, Name, BillingCity, BillingState, VSA_Name__c, Divisions__c, Verification_Date__c from Account where RecordTypeID = '01250000000DQkZ'limit 1000];
}
return accs;
}
public void doSort()
{
String order = 'asc';
/*This checks to see if the same header was clicked two times in a row, if so
it switches the order.*/
if(previousSortField == sortField)
{
order = 'desc';
previousSortField = null;
}else
{
previousSortField = sortField;
}
//To sort the table we simply need to use this one line, nice!
superSort.sortList(accs,sortField,order);
}
public static testMethod void TableSortTest()
{
Account a = new Account(name='Test');
insert a;
List<Account> Accounts = new List<Account>
{
new Account(Name='Phoenix',BillingCity='San Jose', BillingState='CA', VSA_Name__c='San Jose', Divisions__c='San Jose'),
new Account(Name='Seguin',BillingCity='Cupertino')
};
insert Accounts;
Test.setCurrentPage(Page.sortabletabletemplate); // Replace with your page's name.
Test.startTest();
ApexPages.currentPage().getParameters().put('id',a.id);
tableSort controller = new tableSort();
System.assertEquals(1000,controller.getaccs().size());
controller.sortField = 'Name';
controller.doSort();
System.assertEquals('Phoenix',controller.getaccs()[0].BillingCity);
controller.doSort();
System.assertEquals('Seguin',controller.getaccs()[0].BillingCity);
controller.sortField='Verification_Date__c';
controller.doSort();
Test.stopTest();
}
}
Here is the superSort Class:
public class superSort {
/*This method takes 3 arguments, the List of objects to sort, the field to sort,
and the order, asc or desc*/
public static void sortList(List<sObject> items, String sortField, String order){
/*I must give credit where it is due as the sorting algorithm I am using is the
one supplied by Andrew Waite here: http://blog.sforce.com/sforce/2008/09/sorting-collect.html */
Boolean isSortFieldReference = false;
Map<Id,String> referenceName;
/*Determine the type of the field that needs to be sorted, if it is a
reference we will want sort by the name of the related object, not the
ID itself*/
if(items[0].getSObjectType().getDescribe().fields.getMap().get(sortField).getDescribe().getType().Name() == 'REFERENCE'){
isSortFieldReference = true;
referenceName = new Map<Id,String>();
/*Determine the type of this object and populate the Id to Name map*/
Set<Id> referenceIds = new Set<Id>();
for(sObject s : items){
referenceIds.add((Id)s.get(sortField));
}
// DevAngel - EDIT - Because you may not have a value for the reference field in the first record
// in the table you are sorting, this approach will fail on the substring method. Below is
// is a more reliable method using describe calls
/*
String objectID = (String)items[0].get(sortField);
String prefix = objectID.substring(0,3);
String objectType;
Map<String, Schema.SObjectType> gd = Schema.getGlobalDescribe();
for(Schema.SObjectType s : gd.values()){
if(prefix == s.getDescribe().getKeyPrefix()){
objectType = s.getDescribe().Name;
}
}
*/
// DevAngel - EDIT - New approach...
List<Schema.Sobjecttype> objType = items[0].getSObjectType().getDescribe().fields.getMap().get(sortField).getDescribe().getReferenceTo();
String objectType = objType[0].getDescribe().getName();
//Query the related objects for the name and populate the Id -> Name map
String queryString = 'select Id, Name from ' + objectType + ' where ID IN :referenceIDs';
for(sObject s : Database.query(queryString )){
// DevAngel - EDIT - if the reference field is null then we will not have a result, so we need to "create one"
if (s.get('Name') == null) {
referenceName.put((Id)s.get('Id'), 'n/a');
} else {
referenceName.put((Id)s.get('Id'),(String)s.get('Name'));
}
}
}
/*Declare a list that will contain the sorted results. I think this is one of the
coolest parts of this method as the system will not let you declare a list of
sObjects (List<sObject> objects = new List<sObjects>();) but using a
wrapper class you can bypass this system limitation to create this type of list */
List<cObject> resultList = new List<cObject>();
//Create a map that can be used for sorting
Map<object, List<cObject>> objectMap = new Map<object, List<cObject>>();
for(sObject ob : items){
if(isSortFieldReference == false){
if(objectMap.get(ob.get(sortField)) == null){
objectMap.put(ob.get(sortField), new List<cObject>());
}
cObject o = new cObject(ob);
objectMap.get(ob.get(sortField)).add(o);
}else{
if(objectMap.get(referenceName.get((Id)ob.get(sortField))) == null){
objectMap.put(referenceName.get((Id)ob.get(sortField)), new List<cObject>());
}
cObject o = new cObject(ob);
objectMap.get(referenceName.get((Id)ob.get(sortField))).add(o);
}
}
//Sort the keys
List<object> keys = new List<object>(objectMap.keySet());
keys.sort();
for(object key : keys){
resultList.addAll(objectMap.get(key));
}
//Apply the sorted values to the source list
items.clear();
if(order.toLowerCase() == 'asc'){
for(cObject ob : resultList){
items.add(ob.obj);
}
}else if(order.toLowerCase() == 'desc'){
for(integer i = resultList.size()-1; i >= 0; i--){
items.add(resultList[i].obj);
}
}
}
public class cObject{
sObject obj {get; set;}
public cObject(sObject obj){
this.obj = obj;
}
}
/*Some test methods that provide 100% coverage */
public static testMethod void sortAscendingTest() {
Id Owner;
List<Account> accs = new List<Account>();
Owner = [SELECT id FROM User LIMIT 1].id;
for(integer i = 0; i<1000; i++) {
Account a = new Account();
a.Name='Test' + i;
a.AnnualRevenue=1000 * Math.random();
a.OwnerId = Owner;
accs.add(a);
}
// accs.add(new Account(Name = 'test' + i, Annualized_Revenue__c = 1000 * Math.random()));
Test.startTest();
Long start = system.currentTimeMillis();
sortList(accs,'OwnerId','asc');
system.debug(system.currentTimeMillis() - start);
Test.stopTest();
//Assert the list was sorted correctly
}
}
All Answers
the main problem is with "referenceName" - cannot think of how to add this to test
Here is what I finally worked out:
public with sharing class tableSort
{
List<Account> accs;
public String sortField {get; set;}
public String previousSortField {get; set;}
public List<Account> getaccs()
{
if(accs == null){
accs = [select Id, Name, BillingCity, BillingState, VSA_Name__c, Divisions__c, Verification_Date__c from Account where RecordTypeID = '01250000000DQkZ'limit 1000];
}
return accs;
}
public void doSort()
{
String order = 'asc';
/*This checks to see if the same header was clicked two times in a row, if so
it switches the order.*/
if(previousSortField == sortField)
{
order = 'desc';
previousSortField = null;
}else
{
previousSortField = sortField;
}
//To sort the table we simply need to use this one line, nice!
superSort.sortList(accs,sortField,order);
}
public static testMethod void TableSortTest()
{
Account a = new Account(name='Test');
insert a;
List<Account> Accounts = new List<Account>
{
new Account(Name='Phoenix',BillingCity='San Jose', BillingState='CA', VSA_Name__c='San Jose', Divisions__c='San Jose'),
new Account(Name='Seguin',BillingCity='Cupertino')
};
insert Accounts;
Test.setCurrentPage(Page.sortabletabletemplate); // Replace with your page's name.
Test.startTest();
ApexPages.currentPage().getParameters().put('id',a.id);
tableSort controller = new tableSort();
System.assertEquals(1000,controller.getaccs().size());
controller.sortField = 'Name';
controller.doSort();
System.assertEquals('Phoenix',controller.getaccs()[0].BillingCity);
controller.doSort();
System.assertEquals('Seguin',controller.getaccs()[0].BillingCity);
controller.sortField='Verification_Date__c';
controller.doSort();
Test.stopTest();
}
}
Here is the superSort Class:
public class superSort {
/*This method takes 3 arguments, the List of objects to sort, the field to sort,
and the order, asc or desc*/
public static void sortList(List<sObject> items, String sortField, String order){
/*I must give credit where it is due as the sorting algorithm I am using is the
one supplied by Andrew Waite here: http://blog.sforce.com/sforce/2008/09/sorting-collect.html */
Boolean isSortFieldReference = false;
Map<Id,String> referenceName;
/*Determine the type of the field that needs to be sorted, if it is a
reference we will want sort by the name of the related object, not the
ID itself*/
if(items[0].getSObjectType().getDescribe().fields.getMap().get(sortField).getDescribe().getType().Name() == 'REFERENCE'){
isSortFieldReference = true;
referenceName = new Map<Id,String>();
/*Determine the type of this object and populate the Id to Name map*/
Set<Id> referenceIds = new Set<Id>();
for(sObject s : items){
referenceIds.add((Id)s.get(sortField));
}
// DevAngel - EDIT - Because you may not have a value for the reference field in the first record
// in the table you are sorting, this approach will fail on the substring method. Below is
// is a more reliable method using describe calls
/*
String objectID = (String)items[0].get(sortField);
String prefix = objectID.substring(0,3);
String objectType;
Map<String, Schema.SObjectType> gd = Schema.getGlobalDescribe();
for(Schema.SObjectType s : gd.values()){
if(prefix == s.getDescribe().getKeyPrefix()){
objectType = s.getDescribe().Name;
}
}
*/
// DevAngel - EDIT - New approach...
List<Schema.Sobjecttype> objType = items[0].getSObjectType().getDescribe().fields.getMap().get(sortField).getDescribe().getReferenceTo();
String objectType = objType[0].getDescribe().getName();
//Query the related objects for the name and populate the Id -> Name map
String queryString = 'select Id, Name from ' + objectType + ' where ID IN :referenceIDs';
for(sObject s : Database.query(queryString )){
// DevAngel - EDIT - if the reference field is null then we will not have a result, so we need to "create one"
if (s.get('Name') == null) {
referenceName.put((Id)s.get('Id'), 'n/a');
} else {
referenceName.put((Id)s.get('Id'),(String)s.get('Name'));
}
}
}
/*Declare a list that will contain the sorted results. I think this is one of the
coolest parts of this method as the system will not let you declare a list of
sObjects (List<sObject> objects = new List<sObjects>();) but using a
wrapper class you can bypass this system limitation to create this type of list */
List<cObject> resultList = new List<cObject>();
//Create a map that can be used for sorting
Map<object, List<cObject>> objectMap = new Map<object, List<cObject>>();
for(sObject ob : items){
if(isSortFieldReference == false){
if(objectMap.get(ob.get(sortField)) == null){
objectMap.put(ob.get(sortField), new List<cObject>());
}
cObject o = new cObject(ob);
objectMap.get(ob.get(sortField)).add(o);
}else{
if(objectMap.get(referenceName.get((Id)ob.get(sortField))) == null){
objectMap.put(referenceName.get((Id)ob.get(sortField)), new List<cObject>());
}
cObject o = new cObject(ob);
objectMap.get(referenceName.get((Id)ob.get(sortField))).add(o);
}
}
//Sort the keys
List<object> keys = new List<object>(objectMap.keySet());
keys.sort();
for(object key : keys){
resultList.addAll(objectMap.get(key));
}
//Apply the sorted values to the source list
items.clear();
if(order.toLowerCase() == 'asc'){
for(cObject ob : resultList){
items.add(ob.obj);
}
}else if(order.toLowerCase() == 'desc'){
for(integer i = resultList.size()-1; i >= 0; i--){
items.add(resultList[i].obj);
}
}
}
public class cObject{
sObject obj {get; set;}
public cObject(sObject obj){
this.obj = obj;
}
}
/*Some test methods that provide 100% coverage */
public static testMethod void sortAscendingTest() {
Id Owner;
List<Account> accs = new List<Account>();
Owner = [SELECT id FROM User LIMIT 1].id;
for(integer i = 0; i<1000; i++) {
Account a = new Account();
a.Name='Test' + i;
a.AnnualRevenue=1000 * Math.random();
a.OwnerId = Owner;
accs.add(a);
}
// accs.add(new Account(Name = 'test' + i, Annualized_Revenue__c = 1000 * Math.random()));
Test.startTest();
Long start = system.currentTimeMillis();
sortList(accs,'OwnerId','asc');
system.debug(system.currentTimeMillis() - start);
Test.stopTest();
//Assert the list was sorted correctly
}
}