xaizek / zograscope (License: AGPLv3 only) (since 2018-12-07)
Mainly a syntax-aware diff that also provides a number of additional tools.
<root> / tests / tooling / Matcher.cpp (47fc5d741942e208efda79ccce2ac072e6c10f4a) (8,201B) (mode 100644) [raw]
// Copyright (C) 2018 xaizek <xaizek@posteo.net>
//
// This file is part of zograscope.
//
// zograscope is free software: you can redistribute it and/or modify
// it under the terms of version 3 of the GNU Affero General Public License as
// published by the Free Software Foundation.
//
// zograscope is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with zograscope.  If not, see <http://www.gnu.org/licenses/>.

#include "Catch/catch.hpp"

#include "tooling/Matcher.hpp"
#include "mtypes.hpp"
#include "tree.hpp"

#include "tests.hpp"

TEST_CASE("Comment matcher works", "[tooling][matcher][.srcml]")
{
    Matcher matcher(MType::Comment, nullptr);

    int nMatches = 0;

    auto matchHandler = [&](Node */*node*/) {
        ++nMatches;
    };

    SECTION("In Make") {
        Tree tree = parseMake("# this is # a comment");
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 1);
    }
    SECTION("In C") {
        Tree tree = parseC("/* a */ /* b // b */ // c", true);
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 3);
    }
    SECTION("In C++") {
        Tree tree = parseCxx("/* a */ /* b // b */ // c");
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 3);
    }
    SECTION("In Lua") {
        Tree tree = parseLua("--[[a]] --[[b]]");
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 2);
    }
}

TEST_CASE("Directive matcher works", "[tooling][matcher][.srcml]")
{
    Matcher matcher(MType::Directive, nullptr);

    int nMatches = 0;

    auto matchHandler = [&](Node */*node*/) {
        ++nMatches;
    };

    SECTION("In Make") {
        Tree tree = parseMake("-include config.mk");
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 1);
    }
    SECTION("In C") {
        Tree tree = parseC("#include <stdio.h>\n#define a \\b", true);
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 2);
    }
    SECTION("In C++") {
        Tree tree = parseCxx("#include <iostream>\n#define a \\b");
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 2);
    }
}

TEST_CASE("Statement matcher works", "[tooling][matcher][.srcml]")
{
    Matcher matcher(MType::Statement, nullptr);

    int nMatches = 0;

    auto matchHandler = [&](Node */*node*/) {
        ++nMatches;
    };

    SECTION("In C") {
        Tree tree = parseC("void f() { stmt1(); stmt2(); stmt3(); }", true);
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 3);
    }
    SECTION("In C++") {
        Tree tree = parseCxx("void f() { stmt1(); stmt2(); stmt3(); }");
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 3);
    }
    SECTION("In Lua") {
        Tree tree = parseLua("function f() a() v = b() c() end");
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 3);
    }
}

TEST_CASE("Block matcher works", "[tooling][matcher][.srcml]")
{
    Matcher matcher(MType::Block, nullptr);

    int nMatches = 0;

    auto matchHandler = [&](Node */*node*/) {
        ++nMatches;
    };

    SECTION("In C") {
        Tree tree = parseC("void f() { { } { { } } }", true);
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 4);
    }
    SECTION("In C++") {
        Tree tree = parseCxx("void f() { { } { { } } }");
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 4);
    }
    SECTION("In Lua") {
        Tree tree = parseLua("function f() do end end");
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 2);
    }
}

TEST_CASE("Call matcher works", "[tooling][matcher][.srcml]")
{
    Matcher matcher(MType::Call, nullptr);

    int nMatches = 0;

    auto matchHandler = [&](Node */*node*/) {
        ++nMatches;
    };

    SECTION("In Make") {
        Tree tree = parseMake("$(info $(addprefix bla,bla))");
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 2);
    }
    SECTION("In C") {
        Tree tree = parseC("void f() { call1(nested()); call2(); }", true);
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 3);
    }
    SECTION("In C++") {
        Tree tree = parseCxx("void f() { call1(); call2(nested()); }");
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 3);
    }
    SECTION("In Lua") {
        Tree tree = parseLua("call1() call2()");
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 2);
    }
}

TEST_CASE("Parameter matcher works", "[tooling][matcher][.srcml]")
{
    Matcher matcher(MType::Parameter, nullptr);

    int nMatches = 0;

    auto matchHandler = [&](Node */*node*/) {
        ++nMatches;
    };

    SECTION("In C") {
        Tree tree = parseC("void f(int a1, int a2, int a3, int a4) { }", true);
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 4);
    }
    SECTION("In C++") {
        Tree tree = parseCxx("void f(int a1, int a2, int a3, int a4) { }");
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 4);
    }
    SECTION("In Lua") {
        Tree tree = parseLua("function f(a1, a2, a3, a4) ; end");
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 4);
    }
}

TEST_CASE("Declaration matcher works", "[tooling][matcher][.srcml]")
{
    Matcher matcher(MType::Declaration, nullptr);

    int nMatches = 0;

    auto matchHandler = [&](Node */*node*/) {
        ++nMatches;
    };

    SECTION("In C") {
        Tree tree = parseC("int a1; int a2; int a3; int a4;", true);
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 4);
    }
    SECTION("In C++") {
        Tree tree = parseCxx("int a1; int a2; int a3; int a4;");
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 4);
    }
    SECTION("In Lua") {
        Tree tree = parseLua("local a1; local a2; local a3; local a4");
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 4);
    }
}

TEST_CASE("Function matcher works", "[tooling][matcher][.srcml]")
{
    Matcher matcher(MType::Function, nullptr);

    int nMatches = 0;

    auto matchHandler = [&](Node */*node*/) {
        ++nMatches;
    };

    SECTION("In C") {
        Tree tree = parseC("void f() {} void g() {}", true);
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 2);
    }
    SECTION("In C++") {
        Tree tree = parseCxx("void f() {} void g() {}");
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 2);
    }
    SECTION("In Lua") {
        Tree tree = parseLua("function f() end local "
                             "function g() end "
                             "a = function() end");
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 3);
    }
    SECTION("In Bash") {
        Tree tree = parseBash("function f() {\n}\n"
                             "g() {\n}");
        CHECK(matcher.match(tree.getRoot(), *tree.getLanguage(), matchHandler));
        CHECK(nMatches == 2);
    }
}
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/zograscope

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/zograscope

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master