Tomtom
Tomtom

Reputation: 9394

Regex to match TestMethods

For our application we have about 4000 Unit-tests which will be automatically executed if we check-in your code to the tfs.

We've changed a lot at our Build-Definition so now it is required that all unit-tests must have the attribute [TestCategory(TestCategories.GatedCheckin)] to be executed within the gated-checkin.

Unfortunately only 700 Unittest of the 4000 already have this attribute. Now I have to add the attribute to the remaining unit-tests.

Therefor I've written a small VisualStudio-Extension where I can open source file and search for the following regular expression:

^([\t]|[ ])*\[TestMethod\]([\t]|[ ]|[\w\/äÄüÜöÖß])*([\r\n]+)([\t]|[ ])*public

This regular expression just works fine for unit-tests like:

[TestMethod]
public void PathIsValidTest1()
{...}

or

[TestMethod] // another test
public void Calculator_Add_3_And_3_Equals_6_Test()
{...}

But for unittest which also contains another attribute like:

[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void ThrowOnInputTooLongTest2()
{...}

the regular expression doesn't work.

How can I modify the regular expression, so it matches all Unittests with the [TestMethod] attribute and not the [TestCategory(TestCategories.GatedCheckin)]

I thougt about a negative lookahead with ?! but I didn't get it to work.

Any ideas?


I've modified the solution provided by Addison so it looks like:

^[\t ]*\[TestMethod\][ \t\w\/äÄüÜöÖß]*(\n([ \t]*)\[(?!TestCategory\(TestCategories\.GatedCheckin\)).+\][ \t\w\/äÄüÜöÖß]*)?\s+public

If I use this in regex101 it just works fine as you can see here

But if I use this regex in c# with:

string content = File.ReadAllText(file);    
Regex regex = new Regex(pattern, RegexOptions.Multiline);
int matchCount = regex.Matches(content).Count;  

I only get 2 matches.

Upvotes: 2

Views: 723

Answers (1)

Addison
Addison

Reputation: 8397

Great question!

I managed to do it with this:

^[\t ]*\[TestMethod\][ \t\w\/äÄüÜöÖß]*(\n\[(?!TestCategory\(TestCategories\.GatedCheckin\)).+\][ \t\w\/äÄüÜöÖß]*)*\s+public

I added in another catching field (and simplified the rest of the regex) so that it now checks for any number of other [] AFTER the first [TestMethod], and will accept them if and only if none of them are [TestCategory(TestCategories.GatedCheckin)].

Test it online

Here is some C# code to do it:

using System;
using System.Text.RegularExpressions;

namespace Programming {
    class Program {
        static void Main() {
            string content = "namespace MyNameSpace1\n{\n    [TestClass]\n    public class GetMapPathActionTests\n    {\n        [TestMethod] // 1\n        public void GetMapPath_with_All_Attibutes()\n        {\n            ...\n        }\n        [TestMethod] // 2\n        [ExpectedException(typeof(DBInstallInfoConverterCrossCheckerRequiredChildNotFoundException))]\n        public void GetMapPath_with_Empty_Input()\n        {\n           \n        }\n        [TestMethod] // 3\n        [ExpectedException(typeof(DBInstallInfoConverterCrossCheckerRequiredChildNotFoundException))]\n        public void GetMapPath_with_Empty_Output()\n        {\n            \n        }\n        [TestMethod] // 4\n        public void GetMapPath_with_Empty()\n        {\n            \n        }\n        [TestMethod] // 5\n        [ExpectedException(typeof(DBInstallInfoConverterCrossCheckerRequiredChildNotFoundException))]\n        public void GetMapPath_with_All_Attibutes_Empty()\n        {\n            \n        }\n    }\n}\n";
            Regex regex = new Regex(@"^[\t ]*\[TestMethod\][ \t\w\/äÄüÜöÖß]*(\s+\[(?!TestCategory\(TestCategories\.GatedCheckin\)).+\][ \t\w\/äÄüÜöÖß]*)?\s+public", RegexOptions.Multiline);
            MatchCollection matches = regex.Matches(content);

            foreach (Match match in matches) {
                foreach (Capture capture in match.Captures) {
                    Console.WriteLine(capture.Value);
                }
            }
        }
    }
}

Upvotes: 1

Related Questions