/*
如果ab都是图的割点,那么答案非0,反之答案是0
把割点处断开后,原图裂成三张不联通的图,大小分别是size1,size2,size3.
求出同时包含这两个割点的图,设大小是size1,那么答案就是(size2-1)*(size3-1)
*/
#include<bits/stdc++.h>
#include<vector>
using namespace std;
#define ll long long
#define N 500005
vector<int>G[N];
int n,m,a,b;
int low[N],dfn[N],index,cut[N];
void tarjan(int u,int pre){
low[u]=dfn[u]=++index;
int son=0;//统计深搜树上儿子数量
for(auto v:G[u]){
if(v==pre)continue;
if(!dfn[v]){
++son;
tarjan(v,u);
low[u]=min(low[u],low[v]);
if(u!=pre && dfn[u]<=low[v])//非树根割点
cut[u]=true;
}
else low[u]=min(low[u],dfn[v]);
}
if(u==pre && son>1)cut[u]=1;//树根割点
}
int vis[N],flag;
int dfs1(int u){
if(u==a || u==b)flag=1;
int size=1;vis[u]=1;
for(auto v:G[u]){
if(vis[v])continue;
size+=dfs1(v);
}
return size;
}
int dfs2(int u){
if(u==a || u==b)flag=1;
int size=1;vis[u]=1;
for(auto v:G[u]){
if(vis[v])continue;
size+=dfs2(v);
}
return size;
}
int main(){
int t;cin>>t;
while(t--){
scanf("%d%d%d%d",&n,&m,&a,&b);
for(int i=1;i<=n;i++)G[i].clear();
for(int i=1;i<=n;i++)low[i]=dfn[i]=cut[i]=vis[i]=0;
index=0;
for(int i=1;i<=m;i++){
int u,v;scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
tarjan(1,1);
if(!cut[a] || !cut[b]){puts("0");continue;}
//ab将图分成三块,分别求出这三块的size
ll sizea=1;vis[a]=1;
for(auto v:G[a]){
if(vis[v])continue;
flag=0;
int res=dfs1(v);
if(!flag)sizea+=res;
}
for(int i=1;i<=n;i++)vis[i]=0;
ll sizeb=1;vis[b]=1;
for(auto v:G[b]){
if(vis[v])continue;
flag=0;
int res=dfs2(v);
if(!flag)sizeb+=res;
}
cout<<(sizea-1)*(sizeb-1)<<'\n';
}
return 0;
}