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: import jdk.dynalink.beans.StaticClass;
  
  import java.util.*;
  import java.io.*;
  
  public class TrainingSession {
      PrintWriter out;
      StringTokenizer st;
      BufferedReader br;
      final int imax = Integer.MAX_VALUE, imin = Integer.MIN_VALUE;
      final int mod = 1000000007;
  
      void solve() throws Exception {
          int t = 1;
          t = ni();
          for (int ii = 0; ii < t; ii++) {
              int n= ni();
              int[][] arr= new int[n][2];
              for (int i = 0; i < n; i++) arr[i]= ni(2);
  
              int[] mapa= new int[n+1];
              int[] mapb= new int[n+1];
              for(int[] i: arr) {
                  mapa[i[0]]++;
                  mapb[i[1]]++;
              }
  
              long ans= 0l;
              for(int[] i: arr) {
                  ans+= (mapa[i[0]]-1l)* (mapb[i[1]]-1);
              }
  
              out.println(n*(n-1l)*(n-2l)/6- ans);
          }
      }
  
      public static void main(String[] args) throws Exception {
          new TrainingSession().run();
      }
  
      void run() throws Exception {
          if (System.getProperty("ONLINE_JUDGE") == null) {
              File file = new File("./input.txt");
              br = new BufferedReader(new FileReader(file));
              out = new PrintWriter("./output.txt");
          } else {
              out = new PrintWriter(System.out);
              br = new BufferedReader(new InputStreamReader(System.in));
          }
  
          long ss = System.currentTimeMillis();
          st = new StringTokenizer("");
          while (true) {
              try {
                  solve();
              } catch (Exception e) {
                  e.printStackTrace(out);
              } catch (StackOverflowError e) {
                  e.printStackTrace(out);
              }
  
              String s = br.readLine();
              if (s == null) break;
              else st = new StringTokenizer(s);
          }
          //out.println(System.currentTimeMillis()-ss+"ms");
          out.flush();
      }
  
      void read() throws Exception {
          st = new StringTokenizer(br.readLine());
      }
  
      int ni() throws Exception {
          if (!st.hasMoreTokens()) read();
          return Integer.parseInt(st.nextToken());
      }
  
      char nc() throws Exception {
          if (!st.hasMoreTokens()) read();
          return st.nextToken().charAt(0);
      }
  
      String nw() throws Exception {
          if (!st.hasMoreTokens()) read();
          return st.nextToken();
      }
  
      long nl() throws Exception {
          if (!st.hasMoreTokens()) read();
          return Long.parseLong(st.nextToken());
      }
  
      int[] ni(int n) throws Exception {
          int[] ret = new int[n];
          for (int i = 0; i < n; i++) ret[i] = ni();
          return ret;
      }
  
      long[] nl(int n) throws Exception {
          long[] ret = new long[n];
          for (int i = 0; i < n; i++) ret[i] = nl();
          return ret;
      }
  
      double nd() throws Exception {
          if (!st.hasMoreTokens()) read();
          return Double.parseDouble(st.nextToken());
      }
  
      String ns() throws Exception {
          String s = br.readLine();
          return s.length() == 0 ? br.readLine() : s;
      }
  
      void print(int[] arr) {
          for (int i : arr) out.print(i + " ");
          out.println();
      }
  
      void print(long[] arr) {
          for (long i : arr) out.print(i + " ");
          out.println();
      }
  
      void print(int[][] arr) {
          for (int[] i : arr) {
              for (int j : i) out.print(j + " ");
              out.println();
          }
      }
  
      void print(long[][] arr) {
          for (long[] i : arr) {
              for (long j : i) out.print(j + " ");
              out.println();
          }
      }
  
      long add(long a, long b) {
          if (a + b >= mod) return (a + b) - mod;
          else return a + b >= 0 ? a + b : a + b + mod;
      }
  
      long mul(long a, long b) {
          return (a * b) % mod;
      }
  
      void print(boolean b) {
          if (b) out.println("YES");
          else out.println("NO");
      }
  
      long binExp(long base, long power) {
          long res = 1l;
          while (power != 0) {
              if ((power & 1) == 1) res = mul(res, base);
              base = mul(base, base);
              power >>= 1;
          }
          return res;
      }
  
      long gcd(long a, long b) {
          if (b == 0) return a;
          else return gcd(b, a % b);
      }
  
      // strictly smaller on left
      void stack_l(int[] arr, int[] left) {
          Stack<Integer> stack = new Stack<>();
          for (int i = 0; i < arr.length; i++) {
              while (!stack.isEmpty() && arr[stack.peek()] >= arr[i]) stack.pop();
              if (stack.isEmpty()) left[i] = -1;
              else left[i] = stack.peek();
              stack.push(i);
          }
      }
  
      // strictly smaller on right
      void stack_r(int[] arr, int[] right) {
          Stack<Integer> stack = new Stack<>();
          for (int i = arr.length - 1; i >= 0; i--) {
              while (!stack.isEmpty() && arr[stack.peek()] >= arr[i]) stack.pop();
              if (stack.isEmpty()) right[i] = arr.length;
              else right[i] = stack.peek();
              stack.push(i);
          }
      }
  
      private void sort(int[] arr) {
          List<Integer> list = new ArrayList<>();
          for (int i : arr) list.add(i);
          Collections.sort(list);
          for (int i = 0; i < arr.length; i++) arr[i] = list.get(i);
      }
  }