/*
author: Apoorv Singh
*/
 
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/detail/standard_policies.hpp>
using namespace std;
using namespace __gnu_pbds;
 
typedef vector <long long> vi;
typedef pair <long long, long long> pii;
#define pb push_back   
#define all(c) c.begin(), c.end()
#define For(i, a, b) for (long long i = a; i < b; ++i)
#define Forr(i, a, b) for (long long i = a; i > b; --i)
#define um unordered_map
#define F first
#define S second
#define int long long
#define inf LLONG_MAX
#define endl "\n"
#define min(a,b) (a < b ? a : b)
#define max(a,b) (a > b ? a : b)
#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize ("O3")
#pragma GCC optimize ("unroll-loops")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#define _CRT_SECURE_NO_WARNINGS
#define fast_io() ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);

#define TRACE
#ifndef ONLINE_JUDGE
#define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
template <typename Arg1>
void __f(const char* name, Arg1&& arg1) {
    cout << name << " : " << arg1 << endl;    
}
template <typename Arg1, typename... Args>
void __f(const char* names, Arg1&& arg1, Args&&... args) {
    const char* comma = strchr(names + 1, ',');cout.write(names, comma - names) << " : " << arg1<<" | ";__f(comma+1, args...);
}
#else
#define trace(...)
#endif

template <class X>
void printarr(X arr[], int n) 
{
    for (int i = 0; i < n; ++i)
        cout << arr[i] << ' ';
    cout << endl;
}

template <typename X> ostream& operator << (ostream& x,const vector<X>& v){ for (X a : v) x << a << ' '; return x;} 
template <typename X, typename Y> ostream& operator << (ostream& x, const vector< pair<X, Y> >& v) {for (pair <X, Y> it : v) x << it.first << ' ' << it.second << endl; return x;} 
template <typename T, typename S> ostream& operator << (ostream& os, const map<T, S>& v) { for (pair <T, S> it : v) os << it.first << " => " << it.second << endl; return os; }
 
template <class T, class cmp = less<T>> using ordered_set = tree<T, null_type, cmp, rb_tree_tag, tree_order_statistics_node_update>;
 
int modulo = 1e9 + 7;

int fpow(int a, int n) 
{
    int ans = 1;
    while (n) 
    {
        if (n&1) ans = (ans*a)%modulo;
        a = (a*a)%modulo; n = n >> 1;
    }
    return ans;
}

const int M = 2e5 + 1;
vi graph[M], tempGraph[M];
int cnt;
int visited[M];

void dfs(int source)
{
    visited[source] = 1;
    ++cnt;
    for (int a : tempGraph[source])
    {
        if (visited[a] != 0) continue;
        dfs(a);
    }
}

signed main() 
{
    fast_io();
    #ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    #endif
    int t; cin >> t;
    while (t--)
    {
        int n,m,a,b; cin >> n >> m >> a >> b;
        For(i,1,n+1)
        {
            graph[i].clear();
            tempGraph[i].clear();
            visited[i] = 0;
        }
        vector <pii> edgesA, edgesB;
        For(i,0,m)
        {
            int u,v; cin >> u >> v;
            if (u == a or v == a or u == b or v == b) 
            {
                if (u == a and v == b or u == b and v == a) continue;
                if (u == a or v == a) edgesA.pb({u,v});
                if (u == b or v == b) edgesB.pb({u,v});
                continue;
            }
            graph[u].pb(v);
            graph[v].pb(u);
        }
        int A = 0, B = 0, C = 0;
        int X = ((n-2)*(n-3))/2;
        
        For(i,1,n+1) 
        {
            for (int z : graph[i]) 
                tempGraph[i].pb(z);
        }
        For(i,1,n+1)
        {
            if (visited[i]) continue;
            if (i == a or i == b) continue;
            cnt = 0;
            dfs(i);
            // trace(i,cnt);
            A += ((cnt)*(cnt-1))/2;
        }

        For(i,1,n+1) 
        {
            for (int z : graph[i]) tempGraph[i].pb(z);
            if (i == a)
            {
                for (pii z : edgesA)
                {
                    tempGraph[z.F].pb(z.S);
                    tempGraph[z.S].pb(z.F);
                }
            }
        }

        For(i,1,n+1) visited[i] = 0;
        For(i,1,n+1)
        {
            if (visited[i] != 0) continue;
            if (i == b) continue;
            cnt = 0;
            dfs(i);
            if (visited[a] == 1)
            { 
                --cnt;
                visited[a] = -1;
            }
            B += ((cnt)*(cnt-1))/2;
        }

        For(i,1,n+1) tempGraph[i].clear();
        For(i,1,n+1) 
        {
            for (int z : graph[i]) tempGraph[i].pb(z);
            if (i == b)
            {
                for (pii z : edgesB)
                {
                    tempGraph[z.F].pb(z.S);
                    tempGraph[z.S].pb(z.F);
                }
            }
        }

        For(i,1,n+1) visited[i] = 0;
        For(i,1,n+1)
        {
            if (visited[i] != 0) continue;
            if (i == a) continue;
            cnt = 0;
            dfs(i);
            if (visited[b] == 1)
            { 
                --cnt;
                visited[b] = -1;
            }
            C += ((cnt)*(cnt-1))/2;
        }

        cout << X-B-C+A << endl;
    }
    return 0;
}