description: Monocarp is the coach of the Berland State University programming teams. He decided to compose a problemset for a training session for his teams.
  
  Monocarp has n problems that none of his students have seen yet. The i-th problem has a topic a_i (an integer from 1 to n) and a difficulty b_i (an integer from 1 to n). All problems are different, that is, there are no two tasks that have the same topic and difficulty at the same time.
  
  Monocarp decided to select exactly 3 problems from n problems for the problemset. The problems should satisfy at least one of two conditions (possibly, both):
  
    * the topics of all three selected problems are different; 
    * the difficulties of all three selected problems are different. 
  
  
  
  Your task is to determine the number of ways to select three problems for the problemset.
  
  Input
  
  The first line contains a single integer t (1 ≤ t ≤ 50000) — the number of testcases.
  
  The first line of each testcase contains an integer n (3 ≤ n ≤ 2 ⋅ 10^5) — the number of problems that Monocarp have.
  
  In the i-th of the following n lines, there are two integers a_i and b_i (1 ≤ a_i, b_i ≤ n) — the topic and the difficulty of the i-th problem.
  
  It is guaranteed that there are no two problems that have the same topic and difficulty at the same time.
  
  The sum of n over all testcases doesn't exceed 2 ⋅ 10^5.
  
  Output
  
  Print the number of ways to select three training problems that meet either of the requirements described in the statement.
  
  Example
  
  Input
  
  
  2
  4
  2 4
  3 4
  2 1
  1 3
  5
  1 5
  2 4
  3 3
  4 2
  5 1
  
  
  Output
  
  
  3
  10
  
  Note
  
  In the first example, you can take the following sets of three problems:
  
    * problems 1, 2, 4; 
    * problems 1, 3, 4; 
    * problems 2, 3, 4. 
  
  
  
  Thus, the number of ways is equal to three.
solution: // Problem: D. Training Session
  // Contest: Codeforces - Educational Codeforces Round 115 (Rated for Div. 2)
  // URL: https://codeforces.com/contest/1598/problem/D
  // Memory Limit: 256 MB
  // Time Limit: 2000 ms
  // 
  // Powered by CP Editor (https://cpeditor.org)
  
  import java.io.*;
  import java.util.*;
  import java.math.*;
  import static java.lang.Math.max;
  import static java.lang.Math.min;
  import static java.lang.Math.abs;
  
  
  /**
   * zxz 
   * problem link:
   **/
  public class Main {
      //put some data here
  
      /**
       * do some clean action before next testcase
       */
      private void clear() {
  
      }
  	long [] dp = new long[200001];
  
      private void solve() throws Exception {
          rf();
          int n = readInt();
          // int m = readInt();
          ArrayList<ArrayList<Integer>> list = new ArrayList<>(n + 1);
          for(int i = 0; i <= n; i++){
          	list.add(new ArrayList<Integer>());
          }
          int [] cnt = new int[n + 1];
          for(int i = 0; i < n; i++){
          	rf();
          	int a = readInt();
          	int b = readInt();
          	list.get(a).add(b);
          	cnt[b]++;
          }
          long ans = dp[n];
          for(int i = 1; i <= n; i++){
          	int t = list.get(i).size();
          	if(t >= 2){
          		t -= 1;
          		for(int to : list.get(i)){
          			ans -= (long)(cnt[to] - 1) * t;
          		}
          	}
          }
          addAns(ans);
  
      }
  
      private void run() throws Exception {
  		dp[3] = 1;
  		dp[4] = 4;
  		BigInteger big = new BigInteger(4 + "");
  		for(int i = 5; i <= 200000; i++){
  			big = big.multiply(new BigInteger(i + "")).divide(new BigInteger((i - 3) + ""));
  			dp[i] = big.longValue();
  			// if(i == 200000){
  				// addAns(dp[i]);
  			// }
  		}
         rf();
         int T = readInt();
          // int T = 1;
  
          while (T-- > 0) {
              solve();
              if (T != 0) {
                  clear();
              }
          }
          printAns();
      }
  
      public static void main(String[] args) throws Exception {
          new Main().run();
      }
  
      StringBuilder sb = new StringBuilder();
      BufferedReader infile = new BufferedReader(new InputStreamReader(System.in));
      StringTokenizer st;
  
  	private void addAns(int a){
  		sb.append(a + "\n");
  	}
  	
  	private void addAns(long a){
  		sb.append(a + "\n");
  	}
  	
  	private void addAns(String s){
  		sb.append(s + "\n");
  	}
  
      private void rf() throws IOException {
          st = new StringTokenizer(infile.readLine());
      }
  
      private int readInt() {
          return Integer.parseInt(st.nextToken());
      }
  
      private long readLong() {
          return Long.parseLong(st.nextToken());
      }
  
  
      private void printAns() {
          System.out.println(sb);
      }
  
      private int[] readArr(int N) throws Exception {
          int[] arr = new int[N];
          rf();
          for (int i = 0; i < N; i++) {
              arr[i] = Integer.parseInt(st.nextToken());
          }
          return arr;
      }
  
      private void print(int[] arr) {
          //for debugging only
          for (int x : arr) {
              System.out.print(x + " ");
          }
          System.out.println();
      }
  
      private long[] readArr2(int N) throws Exception {
          long[] arr = new long[N];
          st = new StringTokenizer(infile.readLine());
          for (int i = 0; i < N; i++) {
              arr[i] = Long.parseLong(st.nextToken());
          }
          return arr;
      }
  
      private boolean isPrime(long n) {
          if (n < 2) {
              return false;
          }
          if (n == 2 || n == 3) {
              return true;
          }
          if (n % 2 == 0 || n % 3 == 0) {
              return false;
          }
          long sqrtN = (long) Math.sqrt(n) + 1;
          for (long i = 6L; i <= sqrtN; i += 6) {
              if (n % (i - 1) == 0 || n % (i + 1) == 0) {
                  return false;
              }
          }
          return true;
      }
  
      private long gcd(long a, long b) {
          if (a > b) {
              a = (a + b) - (b = a);
          }
          if (a == 0L) {
              return b;
          }
          return gcd(b % a, a);
      }
      
      private double pow(double x, long N) {
          double ans = 1.0;
          // 贡献的初始值为 x
          double x_contribute = x;
          // 在对 N 进行二进制拆分的同时计算答案
          while (N > 0) {
              if (N % 2 == 1) {
                  // 如果 N 二进制表示的最低位为 1，那么需要计入贡献
                  ans *= x_contribute;
              }
              // 将贡献不断地平方
              x_contribute *= x_contribute;
              // 舍弃 N 二进制表示的最低位，这样我们每次只要判断最低位即可
              N /= 2;
          }
          return ans;
      }
      
      long pow_mod(long x, long i, long mod){
  	    if(i == 0){
  	        return 1;
  	    }
  	    long temp = pow_mod(x, i >> 1, mod);
  	    temp = temp * temp % mod;
  	    if((i & 1 )!= 0){
  	        temp = temp * x % mod;
  	    }
  	    return temp;
  	}
      
  
  }
  