code: def test_parse_grammar(self) -> None:
      grammar_source = """
          start: sum NEWLINE
          sum: t1=term '+' t2=term { action } | term
          term: NUMBER
          """
      expected = """
          start: sum NEWLINE
          sum: term '+' term | term
          term: NUMBER
          """
      grammar: Grammar = parse_string(grammar_source, GrammarParser)
      rules = grammar.rules
      self.assertEqual(str(grammar), textwrap.dedent(expected).strip())
      # Check the str() and repr() of a few rules; AST nodes don't support ==.
      self.assertEqual(str(rules["start"]), "start: sum NEWLINE")
      self.assertEqual(str(rules["sum"]), "sum: term '+' term | term")
      expected_repr = "Rule('term', None, Rhs([Alt([NamedItem(None, NameLeaf('NUMBER'))])]))"
      self.assertEqual(repr(rules["term"]), expected_repr)
  
imports: import ast
  import difflib
  import io
  import textwrap
  import unittest
  from test import test_tools
  from typing import Dict, Any
  from tokenize import TokenInfo, NAME, NEWLINE, NUMBER, OP
label_desc: Use image node_id 1 for calling the TestPegen obj's underlying member method code with example usage: obj.test_parse_grammar() without return types