MapGesture.OnGestureListener to let user select route they want - if-statement

UPDATE BELOW!!
I'm trying to let the user decide which of the 3 routes provided, they want to take. Here is the screenshot of the routes.
I am using the HERE SDK FOR ANDROID (PREMIUM EDITION) 3.18.5
Here is my code for adding the routes to the map:
coreRouter.calculateRoute(routePlan,
object : Router.Listener<List<RouteResult>, RoutingError> {
override fun onProgress(i: Int) {
}
override fun onCalculateRouteFinished(
routeResults: List<RouteResult>,
routingError: RoutingError
) {
if (routingError === RoutingError.NONE) {
routeResultsList = routeResults
if (routeResults[0].route != null) {
route = routeResults[0].route
mapRoute = MapRoute(routeResults[0].route)
mapRoute!!.isManeuverNumberVisible = true
mapRoute!!.zIndex = 3
mapRoute!!.tag = "0"
map!!.addMapObject(mapRoute!!)
geoBoundingBox = routeResults[0].route.boundingBox
geoBoundingBox!!
map!!.zoomTo(
geoBoundingBox!!, Map.Animation.NONE, 5f
)
timeDistanceForCL()
if (onPause == 1) {
startNavigation()
}
} else {
Toast.makeText(
this#Route,
"Error: route results returned is not valid",
Toast.LENGTH_LONG
).show()
}
if (routeResults[1].route != null) {
route = routeResults[1].route
mapRoute = MapRoute(routeResults[1].route)
mapRoute!!.isManeuverNumberVisible = true
mapRoute!!.color = ContextCompat.getColor(this#Route, R.color.gray_lines)
mapRoute!!.zIndex = 2
mapRoute!!.tag = "1"
map!!.addMapObject(mapRoute!!)
if (onPause == 1) {
startNavigation()
}
} else {
Toast.makeText(
this#Route,
"Error: route results returned is not valid",
Toast.LENGTH_LONG
).show()
}
if (routeResults[2].route != null) {
route = routeResults[2].route
mapRoute = MapRoute(routeResults[2].route)
mapRoute!!.isManeuverNumberVisible = true
mapRoute!!.color = ContextCompat.getColor(this#Route, R.color.gray_lines)
mapRoute!!.zIndex = 1
mapRoute!!.tag = "2"
map!!.addMapObject(mapRoute!!)
if (onPause == 1) {
startNavigation()
}
} else {
Toast.makeText(
this#Route,
"Error: route results returned is not valid",
Toast.LENGTH_LONG
).show()
}
} else {
Toast.makeText(
this#Route,
"Error: route calculation returned error code: $routingError",
Toast.LENGTH_LONG
).show()
}
}
})
When I add them to the map, I make the first route the normal color, then the other two are in grey and they have a lower zIndex as to not cover up the selected route.
I am using the MapGesture.OnGestureListener to determine when one of the routes is selected. Here is the code.
private val mapG: MapGesture.OnGestureListener = object : MapGesture.OnGestureListener.OnGestureListenerAdapter() {
override fun onMapObjectsSelected(p0: MutableList<ViewObject>): Boolean {
Log.d("onMapObjectsSelected", "onMapObjectsSelected ran")
for (p0 in routeResultsList) {
Log.d("onMapObjectsSelected", "onMapObjectsSelected for loop ran ran")
if (p0.route == routeResultsList[0].route){
Log.d("onMapObjectsSelected", "onMapObjectsSelected if(1) ran ran")
route = routeResultsList[0].route
mapRoute = MapRoute(routeResultsList[0].route)
mapRoute!!.isManeuverNumberVisible = true
mapRoute!!.zIndex = 3
map!!.addMapObject(mapRoute!!)
}
if (p0.route == routeResultsList[1].route){
Log.d("onMapObjectsSelected", "onMapObjectsSelected if(2) ran ran")
route = routeResultsList[1].route
mapRoute = MapRoute(routeResultsList[1].route)
mapRoute!!.isManeuverNumberVisible = true
mapRoute!!.zIndex = 3
map!!.addMapObject(mapRoute!!)
}
if (p0.route == routeResultsList[2].route){
Log.d("onMapObjectsSelected", "onMapObjectsSelected if(3) ran ran")
route = routeResultsList[2].route
mapRoute = MapRoute(routeResultsList[2].route)
mapRoute!!.isManeuverNumberVisible = true
mapRoute!!.zIndex = 3
map!!.addMapObject(mapRoute!!)
}
}
return super.onMapObjectsSelected(p0)
}
}
This code keeps the originally selected route [0] highlighted and I thought it was supposed to just highlight the other route that was selected. I haven't worked making the originally selected route grey yet, or update the time and distance at the top of the screen, but when I use the code, it runs all of the Log calls in it.
I'm calling private var mapGestures: MapGesture.OnGestureListener? = null
within the initMapFragmentView() where I have my other calls for NavigationListener.
private fun initMapFragmentView() {
val path = File(getExternalFilesDir(null), ".here-map-data")
.absolutePath
MapSettings.setDiskCacheRootPath(path)
val mapFragment = supportFragmentManager.findFragmentById(R.id.mapFragment) as AndroidXMapFragment?
val context = ApplicationContext(this).apply {
setAppIdCode(s, s1)
setLicenseKey(s2)
}
mapFragment?.let { fragment ->
fragment.init(context) { error ->
when (error) {
OnEngineInitListener.Error.NONE -> {
map = fragment.map
map?.run {
setCenter(
GeoCoordinate(36.9566664, -94.7881218, 0.0),
Map.Animation.NONE
)
setZoomLevel((maxZoomLevel + minZoomLevel) / 2)
}
navigationManager = NavigationManager.getInstance()
navigationManager!!.distanceUnit = NavigationManager.UnitSystem.IMPERIAL_US
navigationManager!!.addRerouteListener(
WeakReference(
mNavigaionRerouteListener
)
)
fragment.mapGesture?.addOnGestureListener(mapG, 0, true)
navigationManager!!.realisticViewMode = NavigationManager.RealisticViewMode.DAY
navigationManager!!.addRealisticViewAspectRatio(NavigationManager.AspectRatio.AR_4x3)
navigationManager!!.addRealisticViewListener(
WeakReference(viewListener))
voiceNavigation()
initNavigation()
}
else -> {
val errorMessage = "Error: ${error}, SDK Version: ${Version.getSdkVersion()}"
Toast.makeText(this, errorMessage, Toast.LENGTH_LONG).show();
}
}
}
}
}
Here is the link to the HERE Docs for the Gestures.
I'm not positive if the issue is with the onMapObjectsSelected for loop, or how I have the if statements set up, or something else? When I click on any either of the grey polyLines, then all 3 of them get highlighted instead of just the one that was selected.
UPDATE!!
I have made a few code changes trying to get this to work. In the process I have found out that the values are different for the same MapRoute. For example:
if (routeResults[0].route != null) {
route = routeResults[0].route
mapRoute = MapRoute(routeResults[0].route)
mapRoute0 = MapRoute(routeResults[0].route)
val toAdd = MapRoute(routeResults[0].route)
Log.d("onMapObjectsSelected", "mapRouteList0 $toAdd")
Log.d("onMapObjectsSelected", "mapRoute $mapRoute")
Log.d("onMapObjectsSelected", "mapRoute0 $mapRoute0")
mapRoute!!.isManeuverNumberVisible = true
mapRoute!!.zIndex = 3
mapRoute!!.tag = "0"
mapRouteList.add(toAdd)
map!!.addMapObject(mapRoute!!)
geoBoundingBox = routeResults[0].route.boundingBox
geoBoundingBox!!
map!!.zoomTo(
geoBoundingBox!!, Map.Animation.NONE, 5f
)
timeDistanceForCL()
if (onPause == 1) {
startNavigation()
}
}
This will print out these values:
2021-09-18 12:34:35.356 24400-24400/com.reedscodingandpublishingllc.truckparkingmore D/onMapObjectsSelected: mapRouteList0 com.here.android.mpa.mapping.MapRoute#c5f698ff
2021-09-18 12:34:35.356 24400-24400/com.reedscodingandpublishingllc.truckparkingmore D/onMapObjectsSelected: mapRoute com.here.android.mpa.mapping.MapRoute#c5f68e0f
2021-09-18 12:34:35.356 24400-24400/com.reedscodingandpublishingllc.truckparkingmore D/onMapObjectsSelected: mapRoute0 com.here.android.mpa.mapping.MapRoute#c5f6988f
I'm now trying to find out why the values are different for the same MapRoute(routeResults[0].route) ??
Am I misunderstanding how the MapRoute is named? Because when I go to click on a Route on the map, it comes back with a different value as well. Is there a better way to determine which route a user has selected?

The mapRoute = MapRoute(routeResults[0].route) statement in the above snippet is equivalent to MapRoute m_mapRoute = new MapRoute(route). As you have called the same method thrice, so it has created three different object.
For more details about the MapRoute class, please refer the below API reference document.
https://developer.here.com/documentation/android-premium/3.18/api_reference_java/index.html?com%2Fhere%2Fandroid%2Fmpa%2Fmapping%2FMapRoute.html
Please refer the standard routing and map-gestures implementation examples from the below HERE github repository.
https://github.com/heremaps/here-android-sdk-examples

Related

Update list in Kotlin

So here is my Data Class
data class Bestellung (var id:Int = 0, var anzahl:Int = 1, var speise:String? = null)
my List
private var bestellungList = ArrayList<Bestellung>()
Trying to update the list if "speise" equals "s" but its not working without any error..
if (bestellungList.contains(Bestellung(speise = s))) {
var i = bestellungList.indexOf(Bestellung(speise = s))
bestellungList.set(i, Bestellung(anzahl = +1))
problem is contains
pls try this if you want to check first:
if(bestellungList.any{ it.speise == "s" }) {
// do add logic
} else {
// do something else
}
The problem is your contains part. Replace it like this
val index = bestellungList.indexOfFirst {
it.speise == s
}
if (index >= 0) {
bestellungList[index] = Bestellung(anzahl = +1)
}
if (bestellungList.any{ it.speise == "s" }) {
bestellungList.addAll(Bestellung(anzahl = +1))
} else {
// handle else statement also
}

Search in agresso Query Engine

Is it possible to search/filter on columns with Agresso's QueryEngineService? I've been playing around with SearchCriteria.SearchCriteriaPropertiesList and TemplateResultOptions.Filter but without any luck. I havn't been able to locate any documentation on this matter either.
QueryEngineService.TemplateList templateList = QueryEngineService.GetTemplateList(null, null, Credentials);
var template = templateList.TemplateHeaderList.FirstOrDefault(x => x.Name == strViewName);
if (template == null)
return null;
QueryEngineService.SearchCriteria searchProp = QueryEngineService.GetSearchCriteria(template.TemplateId, false, Credentials);
QueryEngineService.TemplateResultOptions options = QueryEngineService.GetTemplateResultOptions(Credentials);
options.RemoveHiddenColumns = true;
QueryEngineService.InputForTemplateResult input = new QueryEngineService.InputForTemplateResult();
input.TemplateResultOptions = options;
input.TemplateId = template.TemplateId;
input.SearchCriteriaPropertiesList = searchProp.SearchCriteriaPropertiesList;
QueryEngineService.TemplateResultAsDataSet result = QueryEngineService.GetTemplateResultAsDataSet(input, Credentials);
return result.TemplateResult;
You can try to start with this:
List<SearchCriteriaProperties> searchCriteriaProperties = searchCriteria.getSearchCriteriaPropertiesList().getSearchCriteriaProperties();
SearchCriteriaProperties columnFilter = null;
for (SearchCriteriaProperties criteria : searchCriteriaProperties) {
if(criteria.getColumnName().equalsIgnoreCase("ColumnNameHere")) {
columnFilter = criteria;
columnFilter.setRestrictionType("=");
columnFilter.setFromValue("valueToAssign");
}
}
Next is add the columnFilter variable to an instance of the ArrayOfSearchCriteriaProperties() object by using the getSearchCriteriaProperties().add()
ArrayOfSearchCriteriaProperties filter = new ArrayOfSearchCriteriaProperties();
filter.getSearchCriteriaProperties().add(columnFilter);
You can now add the filter object to an instance of the InputForTemplateResult() object.
Working solution (for me)
QueryEngineService.SearchCriteria searchProp = QueryEngineService.GetSearchCriteria(template.TemplateId, false, Credentials);
foreach (QueryEngineService.SearchCriteriaProperties criteria in searchProp.SearchCriteriaPropertiesList)
{
if(criteria.ColumnName.Equals("column_name", StringComparison.OrdinalIgnoreCase))
{
criteria.RestrictionType = "=";
criteria.FromValue = "value";
}
}
//Rest of the code from question above

Duplicate existing contacts alert

In Vtiger 6.5.0 open source, I wants to create a alert function to warn users that the conact's mobile is existing? could you please help me. I'm fresher.
Thanks,
Loi
You can refer the function wich exist in Account module for checking Duplicate Account Name.
Please follow this files you will get an idea.
This is the code flow how its done In Account Module
Registring Pre Save Event
http://code.vtiger.com/vtiger/vtigercrm/blob/master/layouts/vlayout/modules/Accounts/resources/Edit.js#L250
This teh Fucntion to check Duplicate in cache, If not calls the Helper function
http://code.vtiger.com/vtiger/vtigercrm/blob/master/layouts/vlayout/modules/Accounts/resources/Edit.js#L83
This the Helper function which makes the call to server
http://code.vtiger.com/vtiger/vtigercrm/blob/master/resources/helper.js#L166
This is the action function which is responsible for Serving the request which came from Helper Function
http://code.vtiger.com/vtiger/vtigercrm/blob/master/modules/Accounts/actions/CheckDuplicate.php#L30
And this is the function which checks for Duplicate
http://code.vtiger.com/vtiger/vtigercrm/blob/master/modules/Accounts/models/Record.php#L57
Hope this helps.
Hi Victor please follow this steps
modules\Leads\actions\Checkprimaryemail.php
<?php
class Leads_Checkprimaryemail_Action extends Vtiger_BasicAjax_Action {
public function checkPermission(Vtiger_Request $request) {
return;
}
public function process(Vtiger_Request $request) {
global $adb;
$moduleName = $request->get('module');
$recordId = $request->get('recordId');
$primary_email = $request->get('primary_email');
/*Lead Details*/
$lead_query = "select * from vtiger_leaddetails
inner join vtiger_crmentity on vtiger_crmentity.crmid=vtiger_leaddetails.leadid
where vtiger_crmentity.deleted = 0 and vtiger_leaddetails.email='".$primary_email."'";
$lead_result = $adb->query($lead_query);
$lead_email = $adb->query_result($lead_result,0,'email');
$lead_numrows = $adb->num_rows($lead_result);
/*Contact Details*/
$cont_query = "select * from vtiger_contactdetails
inner join vtiger_crmentity on vtiger_crmentity.crmid=vtiger_contactdetails.contactid
where vtiger_crmentity.deleted = 0 and vtiger_contactdetails.email='".$primary_email."'";
$cont_result = $adb->query($cont_query);
$cont_email = $adb->query_result($cont_result,0,'email');
$cont_numrows = $adb->num_rows($cont_result);
if($recordId != '' ){
if($primary_email == $lead_email && $lead_numrows == 1 ){
$emailtrue = 0;
} elseif($primary_email == $cont_email && $cont_numrows >= 1 ) {
$emailtrue = 1;
}
} else {
if(($lead_numrows >=1 || $cont_numrows >=1 ) || ($lead_numrows >=1 && $cont_numrows >= 1) ){
$emailtrue = 1;
} else {
$emailtrue = 0;
}
}
$emailData = array($emailtrue);
$response = new Vtiger_Response();
$response->setResult($emailData);
$response->emit();
}
}
?>
After Create One other file
layouts\vlayout\modules\Leads\resources\Edit.js
Vtiger_Edit_Js("Leads_Edit_Js", {
}, {
changeEvent: function (container) {
jQuery('input[name="email"]').on('focusout', function (e) {
var email = jQuery('input[name="email"]').val();
var recordId = jQuery('input[name="record"]').val();
var email_length = email.length;
if (email != '') {
if (email_length > 100) {
var errorMessage = app.vtranslate('JS_EMAIL_LENGTH_VALIDATION');
params = {
text: errorMessage,
'type': 'error',
};
Vtiger_Helper_Js.showMessage(params);
}
var progressIndicatorElement = jQuery.progressIndicator({
'position': 'html',
'blockInfo': {
'enabled': true
}
});
var postData = {
"module": 'Leads',
"action": "Checkprimaryemail",
"primary_email": email,
"recordId": recordId
}
AppConnector.request(postData).then(
function (data) {
progressIndicatorElement.progressIndicator({'mode': 'hide'});
if (data['result'] == 1) {
jQuery('#emailalready_exists').val(1);
var errorMessage = app.vtranslate('JS_EMAIL_EXIST');
params = {
text: errorMessage,
'type': 'error',
};
Vtiger_Helper_Js.showMessage(params);
} else {
jQuery('#emailalready_exists').val(0);
}
},
function (error, err) {}
);
e.preventDefault();
}
});
},
registerBasicEvents: function (container) {
this._super(container);
this.changeEvent(container);
}
});
To check duplicate records in vTiger follow below steps:
Register checkDuplicate function in registerBasicEvents
1: \layouts\vlayout\modules\Contacts\resources\Edit.js
getmobile : function(container){
return jQuery('input[name="mobile"]',container).val();
},
getRecordId : function(container){
return jQuery('input[name="record"]',container).val();
},
DuplicateCheck : function(form) {
var thisInstance = this;
if(typeof form == 'undefined') {
form = this.getForm();
}
jQuery( "#mobileFieldId" ).change(function() {
var mobile = thisInstance.getmobile(form);
var recordId = thisInstance.getRecordId(form);
var params = {
'module' : "Contacts",
'action' : "CheckDuplicate",
'mobile' : mobile,
'record' : recordId
}
AppConnector.request(params).then(
function(data) {
var response = data['result'];
var result = response['success'];
if(result == true) {
var message_params = {
title : app.vtranslate('JS_MESSAGE'),
text: response['message'],
animation: 'show',
type: 'error'
};
Vtiger_Helper_Js.showPnotify(message_params);
jQuery(".btn-success").attr('disabled',true);
return false;
} else {
jQuery(".btn-success").attr('disabled',false);
}
}
);
});
},
2: Create new file in** \modules\Contacts\actions\CheckDuplicate.php
Follow the same process / code as given in \modules\Accounts\actions\CheckDuplicate.php
3: Add new function checkDuplicate() in \modules\Contacts\models\Record.php
And follow same process as given in \modules\Accounts\models\Record.php having function checkDuplicate()
Note: Don't forget to change the db table name, class name module wise.
Hope this will help you. Thank you.

How to unit test unformatted method in mvc?

I have to unit test one of the very big and unformatted method in ASP.NET MVC 4.0.
Below is the code of action method :-
public ActionResult GetDetails(string ProdName, int ProdArea, int ProdAreaId= 0)
{
if (ProdAreaId == 0 && ProdArea == 1 && System.Web.HttpContext.Current.Session["ResponseProdAreaId"] != null)
{
ProdAreaId = (int)System.Web.HttpContext.Current.Session["ResponseProdAreaId"];
}
if (string.IsNullOrEmpty(ProdName))
{
if (System.Web.HttpContext.Current.Session["ProdName"] == null)
{
ProdName = Guid.NewGuid().ToString();
System.Web.HttpContext.Current.Session["ProdName"] = ProdName;
}
else
{
ProdName = System.Web.HttpContext.Current.Session["ProdName"].ToString();
}
}
else
{
ProdName = ProdName.Replace("___", " ");
}
List<StateDetail> stateList = ProductService.GetAllStates().Where(n => n.FKCountryID == (int)Countries.UnitedStates).ToList();
ProductAddressViewModel model = new ProductAddressViewModel
{
ProdArea = ProdArea,
FKProductID = CurrentProductId
};
model.States = stateList != null ? new SelectList(stateList, "StateID", "StateCode") : null;
if (System.Web.HttpContext.Current.Session[“ProdAddresses”] != null && ProdAreaId == 0 && ProdArea == 1)
{
List<ProductAddressDto> lstprodaddresses = (List<ProductAddressDto>)System.Web.HttpContext.Current.Session[“ProdAddresses”];
if (lstprodaddresses.Count > 0)
{
AddressDto addrDto = lstprodaddresses.First().Address;
//save address in DB
model.Address1 = addrDto.Address1;
model.Address2 = addrDto.Address2;
model.ProdArea = 1;
model.City = addrDto.City;
model.IsDefault = true;
model.ProdName = model.ProdName;
model.SelectedAddressTypeID = (int)AddressType.Street;
model.ZIPCode = addrDto.ZIPCode;
model.SelectedStateId = addrDto.FKStateID;
model.AddressTypes = GetAddressTypes();
}
}
else if (model.FKProductID > 0)
{
ToolDto tool = ToolService.GetToolDetails(model.FKProductID);
if (ProdAreaId > 0)
{
model.AddressTypes = GetAddressTypes();
ProductAddressDto prodaddr = tool.ToolAddresses.First(n => n.Tool_AddressID == ProdAreaId);
model.Address1 = prodaddr.Address.Address1;
model.Address2 = prodaddr.Address.Address2;
model.City = prodaddr.Address.City;
model.SelectedStateId = prodaddr.Address.FKStateID;
model.ZIPCode = prodaddr.Address.ZIPCode;
model.SelectedAddressTypeID = prodaddr.Address.FKAddressTypeID;
model.IsDefault = prodaddr.IsDefault;
model.FKAddressID = prodaddr.FKAddressID;
model.Tool_AddressID = prodaddr.Tool_AddressID;
model.FKProductID = prodaddr.FKProductID;
model.AddressTypes = GetAddressTypes();
}
else
{
//address types
List<int> excludeAddrTypes = new List<int>();
foreach (ProductAddressDto prodadrdto in tool.ToolAddresses)
{
if (prodadrdto.Tool_AddressID != ProdAreaId)
{
excludeAddrTypes.Add(prodadrdto.Address.FKAddressTypeID);
}
}
if (System.Web.HttpContext.Current.Session[“ProdAddresses”] != null)
{
excludeAddrTypes.Add((int)AddressType.Street);
}
var addrtypes = from AddressType e in Enum.GetValues(typeof(AddressType))
where !excludeAddrTypes.Contains((int)e)
select new { Id = (int)e, Name = e.ToString() };
model.AddressTypes = addrtypes.Select(x => new SelectListItem
{
Value = x.Id.ToString(),
Text = x.Name
});
if (tool.ToolAddresses.Count == 0)
{
model.IsDefault = (ProdArea == 1);
}
}
}
else
{
//filter out address types if responsed tool is there
if (System.Web.HttpContext.Current.Session[“ProdAddresses”] != null)
{
List<int> excludeAddrTypes = new List<int>();
excludeAddrTypes.Add((int)AddressType.Street);
var addrtypes = from AddressType e in Enum.GetValues(typeof(AddressType))
where !excludeAddrTypes.Contains((int)e)
select new { Id = (int)e, Name = e.ToString() };
model.AddressTypes = addrtypes.Select(x => new SelectListItem
{
Value = x.Id.ToString(),
Text = x.Name
});
}
else
{
model.AddressTypes = GetAddressTypes();
}
model.IsDefault = (ProdArea == 1);
}
model.ProdName = ProdName;
return PartialView("_AddUpdateAddress", model);
}
May be the method is not in correct format.But i have to do it's unit testing.I have do that in several different ways.But i am not sure about its correctness.
I want to know that how should we do unit test for such a big and unformatted method like this.
Can anyone help me out on this ?
Below is the piece of code of my unit testing method :-
[TestMethod]
public void GetDetailsTest_NotEmpty()
{
var ProdName = random.ToString();
var ProdArea = random.Next();
var ProdAreaId = 0;
var _toolServiceMock = new Mock<IToolService>();
var _lookupServiceMock = new Mock<ILookupService>();
var stateList = new List<StateDto> {
new StateDto() { StateID = random.Next(), StateCode = Guid.NewGuid().ToString(), Description = random.ToString(), FKCountryID = 1 },
new StateDto() { StateID = random.Next(), StateCode = Guid.NewGuid().ToString(), Description = random.ToString(), FKCountryID = random.Next() },
};
_lookupServiceMock.Setup(s => s.GetAllStates()).Returns(stateList); // .Returns(stateList);
//Arrange
CustomerDto cust = _toolService.LookupCustomers("", "").FirstOrDefault();
if (cust != null)
{
ToolDto tool = _toolService.GetToolDetails(cust.Tool.toolId);
if (tool.ToolAddresses.Count > 0 && tool.ToolAddresses.First().Address != null)
{
HttpContext.Current.Session["FKToolID"] = cust.FKToolID;
var controller = new ToolController(_toolServiceMock.Object);
PartialViewResult result = controller.SelectAddress(cust.Tool.Name, 1, tool.ToolAddresses.First().Tool_AddressID) as PartialViewResult;
var viewmodel = (ToolAddressViewModel)((ViewResultBase)(result)).Model;
if (viewmodel != null)
{
//Act
Assert.AreEqual(tool.ToolAddresses.First().Address.Address1, viewmodel.Address1);
Assert.AreEqual("_AddUpdateAddress", result.ViewName);
Assert.IsInstanceOfType(viewmodel, typeof(ToolAddressViewModel));
}
//Act
_lookupServiceMock.VerifyAll();
}
}
}
First of all, your method is a way too complicated and too long.
Make your actions short and with one responsability to respect SOLID principle (http://en.wikipedia.org/wiki/SOLID_(object-oriented_design)).
It will make your methods easier to test.
To help you with your problem, you can do something quick with your code :
Split your actions in internal virtual methods with one concern each (internal to be testable in you unit test project, virtual to be able to mock them).
Put the [assembly: InternalsVisibleTo("YourTestAssembly")] on your controller
In your unit test project, you will be able to test any of your internal methods separately.
Finally, to test your action, use a mocking framework (RhinoMock, Moq) to mock all your internal virtual methods and test the logic of your action (proxies generated by mocking framework will let you mock virtual methods).
It's the easiest way you can test your logic without breaking the existing application.
The inconvenient is that your logic is in internal methods wich let the whole assembly able to use it.

Zend Regex route reverse with paginator

I have following regex route, which allows me to use pagination - to parse URL and also build it:
; route "product-{brand}"
product.type = "Zend_Controller_Router_Route_Regex"
product.route = "product-([a-z\-]+)(?:/page/(\d+)/?)?"
product.defaults.module = "default"
product.defaults.controller = "products"
product.defaults.action = "product"
product.defaults.page = "1"
product.map.1 = "brand"
product.map.2 = "page"
product.reverse = "product-%s/page/%d"
Everything is working fine, however, I need to get the rid of default page. Currently we are migrating old web to the Zend and we need to preserve old links because of current google positions, etc.
With default "page", I'm getting always /page/1, without it Zend "cannot assemble" URL.
How to not display page 1 in URL ?
Finally, I've managed to achieve this, but only by rewriting Regex assemble method.
I'm simply overriding two methods.
Class extension:
class Utils_Router_Regex extends Zend_Controller_Router_Route_Regex
{
// instantiate
public static function getInstance(Zend_Config $config)
{
$defs = ($config->defaults instanceof Zend_Config) ? $config->defaults->toArray() : array();
$map = ($config->map instanceof Zend_Config) ? $config->map->toArray() : array();
$reverse = (isset($config->reverse)) ? $config->reverse : null;
return new self($config->route, $defs, $map, $reverse);
}
// in this case, we are using $this->_reverse as array from config
public function assemble($data = array(), $reset = false, $encode = false, $partial = false)
{
//// EXTENSION PART !!!
if( !isset( $data[(string) $this->_reverse->pagemap]) ) { // if not set url helper
$reverse = $this->_reverse->base;
} else { // if set in url helper
$reverse = $this->_reverse->paginator;
}
/// end of extension part
if ($reverse === null) {
require_once 'Zend/Controller/Router/Exception.php';
throw new Zend_Controller_Router_Exception('Cannot assemble. Reversed route is not specified.');
}
$defaultValuesMapped = $this->_getMappedValues($this->_defaults, true, false);
$matchedValuesMapped = $this->_getMappedValues($this->_values, true, false);
$dataValuesMapped = $this->_getMappedValues($data, true, false);
// handle resets, if so requested (By null value) to do so
if (($resetKeys = array_search(null, $dataValuesMapped, true)) !== false) {
foreach ((array) $resetKeys as $resetKey) {
if (isset($matchedValuesMapped[$resetKey])) {
unset($matchedValuesMapped[$resetKey]);
unset($dataValuesMapped[$resetKey]);
}
}
}
// merge all the data together, first defaults, then values matched, then supplied
$mergedData = $defaultValuesMapped;
$mergedData = $this->_arrayMergeNumericKeys($mergedData, $matchedValuesMapped);
$mergedData = $this->_arrayMergeNumericKeys($mergedData, $dataValuesMapped);
if ($encode) {
foreach ($mergedData as $key => &$value) {
$value = urlencode($value);
}
}
ksort($mergedData);
$return = #vsprintf($reverse, $mergedData);
if ($return === false) {
require_once 'Zend/Controller/Router/Exception.php';
throw new Zend_Controller_Router_Exception('Cannot assemble. Too few arguments?');
}
return $return;
}
}
Then you can define which sprintf string to use:
hodinky.type = "Utils_Router_Regex"
hodinky.route = "hodinky-([a-z\-]+)(?:/page/(\d+)/?)?"
hodinky.defaults.module = "default"
hodinky.defaults.controller = "products"
hodinky.defaults.action = "hodinky"
hodinky.map.1 = "znacka"
hodinky.map.2 = "page"
hodinky.reverse.paginator = "hodinky-%s/page/%d" ; assebmly with paginator
hodinky.reverse.base = "hodinky-%s/" ; assebmly without paginator
hodinky.reverse.pagemap = "page" ; "page" map key
If you have better solution, please let me know.