Resharper DotCover Analyse for Visual Studio Team Services

Do you use Visual Studio Team Services (VSTS) for Builds and/or Releases? Do you use Resharper DotCover? Do you want to use them together? Then boy do I have an extension for you!

That might be a corny introduction, but it is exactly what I have here.

In my current projects we use Resharpers, or also know as Jet Brains, DotCover to run code coverage on all our code. However to run this in VSTS there is a bit of a process to install DotCover on the server and then write a Batch command to execute it with settings. This isn’t the most complex task, but it does give you a dependency to always install this on a server, and have the written Batch script in source control or in the definitions on VSTS. This can cause issues if you forget to get it installed or you need to update the script for every project.

Therefore I got all that magic of the program and cramed it into a pretty package for VSTS. This tool is not reinventing the wheel, but putting some greese on it to run faster. The Build/Release extension simply gives you all the input parameters the program normally offers and then runs them with the packaged version of DotCover that comes with the extension. See simply.

There is however one extra bit of spirit fingers I added into the extension. When researching and running my own tests, I found that some times it is helpful to only run the coverage on certain projects, but to do this you need to specify every project path in the command. Now I don’t know about you, but that sounds boring, so I added an extra field.

Instead of in the Target Arguments passing each project separately and manually, you can pass wildcards in the Project Pattern. If you pass anything in the Project Pattern parameter it will detect you want to use this feature. It then uses the Target Working Directory as the base to recursively search for projects.

For Example: Project Pattern = “*Test.dll” and Target Working Directory = “/Source”

This will search for all DLL that end with ‘Test’ in the ‘Source’ directory and then prepend it to any other arguments in the Target Arguments.

For Example: “/Source/MockTest.dll;/Source/UnitTest.dll”

You can download the extension from the VSTS Marketplace
Here are is a helpful link for Resharper DotCover Analyse – JetBrains
Then this is the GitHub Repository for any issues or some advancements you would like – Pure Random Code GitHub

Update 20-07-2018

There was a recent issue raise on the GitHub Repository that addressed a problem I have also seen before. When running the DotCover from Visual Studio Team Services an error appears as below:

Failed to verify x64 COM object registration: Empty path to COM object.

From the issue raise, the user had linked to a Community Article about “DotCover console runner fails when running as VSTS task“, which in the comments they discussed how to fix this.

To correct it we simply add the following command to the request, that specifies what profiled process bitness to use as they say.

/CoreInstructionSet=[x86|x64]

Therefore the task has now been updated with this field and feature to accomadate this issue and fix. It has been run and tested by myself plus the user that raised the issue, so please enjoy.

MS Word special characters Regex

That pesky Microsoft! They have to be different and mess us developers around don’t they. Have you ever noticed that Microsoft Word’s symbols look a bit different or act a little odd? Well it’s because they are not the standard char characters. This can be a pain for Regex and other things. So how do you get them…

The reason they are so difficult is they use Windows-1252 character encoding set which are not represented in ASCII or ISO-8859-1. This is what just about everyone doesn’t do of course. These characters include:

  • … ellipsis
  • ‘smart’ “quotes”
  • en – dash and em — dash
  • dagger † and double dagger ‡

There are few more of course, but these are the most common few that come up. You can find more of Microsoft Word Windows-1252 character encoding here.

 

Symbol Encoding
single quotes and apostrophe \u2018\u2019\u201A
double quotes \u201C\u201D\u201E
ellipsis \u2026
dashes \u2013\u2014
circumflex \u02C6
open angle bracket \u2039
close angle bracket \u203A
spaces \u02DC\u00A0

 

Here is a pre-built method for JavaScript and C# to combat these.

 

JavaScript Clean String

var wordClean = function(text) {
var cleanStr = text;

// smart single quotes and apostrophe
cleanStr = cleanStr.replace(/[\u2018\u2019\u201A]/g, “\'”);

// smart double quotes
cleanStr = cleanStr.replace(/[\u201C\u201D\u201E]/g, “\””);

// ellipsis
cleanStr = cleanStr.replace(/\u2026/g, “…”);

// dashes
cleanStr = cleanStr.replace(/[\u2013\u2014]/g, “-“);

// circumflex
cleanStr = cleanStr.replace(/\u02C6/g, “^”);

// open angle bracket
cleanStr = cleanStr.replace(/\u2039/g, “<“);

// close angle bracket
cleanStr = cleanStr.replace(/\u203A/g, “>”);

// spaces
cleanStr = cleanStr.replace(/[\u02DC\u00A0]/g, ” “);

return cleanStr ;
}


C# Clean String

public string wordClean (string text){
var cleanStr  = text;

// smart single quotes and apostrophe
cleanStr  = Regex.Replace(s, “[\u2018\u2019\u201A]”, “‘”);

// smart double quotes
cleanStr  = Regex.Replace(s, “[\u201C\u201D\u201E]”, “\””);

// ellipsis
cleanStr  = Regex.Replace(s, “\u2026”, “…”);

// dashes
cleanStr  = Regex.Replace(s, “[\u2013\u2014]”, “-“);

// circumflex
cleanStr  = Regex.Replace(s, “\u02C6”, “^”);

// open angle bracket
cleanStr  = Regex.Replace(s, “\u2039”, “<“);

// close angle bracket
cleanStr  = Regex.Replace(s, “\u203A”, “>”);

// spaces
cleanStr  = Regex.Replace(s, “[\u02DC\u00A0]”, ” “);

return cleanStr ;
}


If you are doing some validation using Regex, here is also how you can check these characters.

JavaScript Regex

function containsWordChar(text) {
var contains;

switch (text) {

case (text.match(/^[\u2018\u2019\u201A]$/)):
contains += “single quotes and apostrophe, “;

case (text.match(/^[\u201C\u201D\u201E]$/)):
contains += “double quotes, “;

case (text.match(/^[\u2026]$/)):
contains += “ellipsis, “;

case (text.match(/^[\u2013\u2014]$/)):
contains += “dashes, “;

case (text.match(/^[\u02C6]$/)):
contains += “circumflex, “;

case (text.match(/^[\u2039]$/)):
contains += “open angle bracket, “;

case (text.match(/^[\u203A]$/)):
contains += “close angle bracket, “;

case (text.match(/^[\u02DC\u00A0]$/)):
contains += “spaces, “;

default:
contains += “double quotes”;

}

return contains;
}


C# Regex (MVC)

[RegularExpression("^[\u2018\u2019\u201A\u201C\u201D\u201E\u2026\u2013\u2014\u02C6\u2039\u203A\u02DC\u00A0]+$", ErrorMessage = "Your content contain some Microsoft Word Windows-1252 character encoding.")]


C# Regex

Public string containsWordChar(text) {
String contains;

switch (text) {

case (text.IsMatch(@”^[\u2018\u2019\u201A]$”)):
contains += “single quotes and apostrophe, “;

case (text.IsMatch(@”^[\u201C\u201D\u201E]$”)):
contains += “double quotes, “;

case (text.IsMatch(@”^[\u2026]$”)):
contains += “ellipsis, “;

case (text.IsMatch(@”^[\u2013\u2014]$”)):
contains += “dashes, “;

case (text.IsMatch(@”^[\u02C6]$”)):
contains += “circumflex, “;

case (text.IsMatch(@”^[\u2039]$”)):
contains += “open angle bracket, “;

case (text.IsMatch(@”^[\u203A]$”)):
contains += “close angle bracket, “;

case (text.IsMatch(@”^[\u02DC\u00A0]$”)):
contains += “spaces, “;

default:
contains += “double quotes”;

}

return contains;
}

 

VAT Number Validation

One bit of code I needed recently was a way to validate a user’s VAT number, but for particular countries. Please see the reasons and method for validating a user’s VAT for most of Europe.

I used the best method of using Regex to match if the user’s entered VAT matches the pattern of the particular countries format. I have seen there are ways to get a master Regex code, but then there are some loop holes in this that some can slip through.  Therefore I opted to put in a Regex string for each country. You can see the source I used and more countries codes at this link https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9781449327453/ch04s21.html

To use the code snippet, just add it to you JavaScript code then add it to an ‘OnChange’ event on the select element with all the countries in. You can change the ‘CountryCode’ to be whatever coding system you us for countries as well, but I went for the widely used 2 digit country codes.


<selectOnChange="return Validate_VATNumber($(this).val(),$('vatField').val())">
<option value="GB">Great Britain<\option>
<option value="AT">Austria<\option>
<option value="BE">Belgium<\option>
</select>


function Validate_VATNumber(CountryCode, UsersVAT) {
    var VATreg='';

    switch (CountryCode) {
        case"GB": //Great Britain
            VATreg="^(GB)?([0-9]{9}([0-9]{3})?|[A-Z]{2}[0-9]{3})$";
            break;
        case"AT": //Austria
            VATreg="^(AT)?U[0-9]{8}$";
            break;
        case"BE": //Belgium
            VATreg="^(BE)?0[0-9]{9}$";
            break;
        case"BG": //Bulgaria
            VATreg="^(BG)?[0-9]{9,10}$";
            break;
        case"HR": //Croatia
            VATreg="";
            break;
        case"CY": //Cyprus
            VATreg="^(CY)?[0-9]{8}L$";
            break;
        case"CZ": //Czech Republic
            VATreg="^(CZ)?[0-9]{8,10}$";
            break;
        case"DK": //Denmark
            VATreg="^(DK)?[0-9]{8}$";
            break;
        case"EE": //Estonia
            VATreg="^(EE)?[0-9]{9}$";
            break;
        case"FI": //Finland
            VATreg="^(FI)?[0-9]{8}$";
            break;
        case"FR": //France
            VATreg="^(FR)?[0-9A-Z]{2}[0-9]{9}$";
            break;
        case"DE": //Germany
            VATreg="^(DE)?[0-9]{9}$";
            break;
        case"GR": //Greece
            VATreg="^(EL|GR)?[0-9]{9}$";
            break;
        case"HU": //Hungary
            VATreg="^(HU)?[0-9]{8}$";
            break;
        case"IT": //Italy
            VATreg="^(IT)?[0-9]{11}$";
            break;
        case"LV": //Latvia
            VATreg="^(LV)?[0-9]{11}$";
            break;
        case"LT": //Lithuania
            VATreg="^(LT)?([0-9]{9}|[0-9]{12})$";
            break;
        case"LU": //Luxembourg
            VATreg="^(LU)?[0-9]{8}$";
            break;
        case"MT": //Malta
            VATreg="^(MT)?[0-9]{8}$";
            break;
        case"NL": //Netherlands
            VATreg="^(NL)?[0-9]{9}B[0-9]{2}$";
            break;
        case"PL": //Poland
            VATreg="^(PL)?[0-9]{10}$";
            break;
        case"PT": //Portugal
            VATreg="^(PT)?[0-9]{9}$";
            break;
        case"RO": //Romania
            VATreg="^(RO)?[0-9]{2,10}$";
            break;
        case"SK": //Slovakia
            VATreg="^(SK)?[0-9]{10}$";
            break;
        case"SI": //Slovenia
            VATreg="^(SI)?[0-9]{8}$";
            break;
        case"ES": //Spain (exc. Canary Islands)
            VATreg="^(ES)?[0-9A-Z][0-9]{7}[0-9A-Z]$";
            break;
        case"SE": //Sweden
            VATreg="^(SE)?[0-9]{12}$";
            break;
     }

    if (VATreg .text(UsersVAT)) {
        //True
    }
    else {
        //False
    }
    returnVATreg .text(UsersVAT)
};