// Path: parboiled-java/src/test/java/org/parboiled/transform/AsmTestUtils.java
// public static String getMethodInstructionList(MethodNode methodNode) {
//     checkArgNotNull(methodNode, "methodNode");
//     Printer printer = new NonMaxTextifier();
//     TraceMethodVisitor traceMethodVisitor = new TraceMethodVisitor(printer);
//     methodNode.accept(traceMethodVisitor);
//     StringWriter stringWriter = new StringWriter();
//     PrintWriter printWriter = new PrintWriter(stringWriter);
//     printer.print(printWriter);
//     printWriter.flush();
//     String[] lines = stringWriter.toString().split("\n");
//     int lineNr = 0;
//     for (int i = 0; i < lines.length; i++) {
//         if (!lines[i].startsWith("  @")) {
//             lines[i] = String.format("%2d %s", lineNr++, lines[i]);
//         }
//     }
//     return "Method '" + methodNode.name + "':\n" + StringUtils.join(lines, "\n") + '\n';
// }
// 
// Path: parboiled-java/src/test/java/org/parboiled/transform/AsmTestUtils.java
// public static void verifyIntegrity(String classInternalName, byte[] classCode) {
//     checkArgNotNull(classCode, "classCode");
//     ClassNode generatedClassNode = new ClassNode(ASMSettings.ASM_API);
//     ClassReader classReader = new ClassReader(classCode);
//     classReader.accept(generatedClassNode, 0);
// 
//     for (Object methodObj : generatedClassNode.methods) {
//         verifyMethodIntegrity(classInternalName, (MethodNode) methodObj);
//     }
// }


import org.parboiled.BaseParser;
import org.parboiled.Rule;
import org.parboiled.annotations.BuildParseTree;
import org.parboiled.annotations.MemoMismatches;
import org.testng.annotations.Test;
import static org.parboiled.transform.AsmTestUtils.getMethodInstructionList;
import static org.parboiled.transform.AsmTestUtils.verifyIntegrity;
import static org.testng.Assert.assertEquals;
    }

    static class Parser3 extends Parser2 {
        @Override Rule B() {
            return Sequence(super.B(), 'B', dup());
        }
        @Override Rule C() {
            return Sequence('C', super.C());
        }
        @SuppressWarnings( {"UnusedDeclaration"})
        Rule D() {
            return Sequence(super.A(), super.B(), B(), dup());
        }
    }

    static class Parser4 extends Parser1 {
        @Override Rule E() {
            return super.E();
        }
    }

    @Test
    public void verifyTestParserHierarchyExtension() throws Exception {
        ParserClassNode classNode = ParserTransformer.extendParserClass(Parser3.class);
        verifyIntegrity(classNode.name, classNode.getClassCode());

        assertEquals(getMethodInstructionList(classNode.getRuleMethods().get("$A()Lorg/parboiled/Rule;")), "" +
                "Method '$A':\n" +
                " 0     GETSTATIC org/parboiled/transform/ParserHierarchyTest$Parser1.EMPTY : Lorg/parboiled/Rule;\n" +
                " 1     ARETURN\n");
// Path: parboiled-java/src/test/java/org/parboiled/transform/AsmTestUtils.java
// public static String getMethodInstructionList(MethodNode methodNode) {
//     checkArgNotNull(methodNode, "methodNode");
//     Printer printer = new NonMaxTextifier();
//     TraceMethodVisitor traceMethodVisitor = new TraceMethodVisitor(printer);
//     methodNode.accept(traceMethodVisitor);
//     StringWriter stringWriter = new StringWriter();
//     PrintWriter printWriter = new PrintWriter(stringWriter);
//     printer.print(printWriter);
//     printWriter.flush();
//     String[] lines = stringWriter.toString().split("\n");
//     int lineNr = 0;
//     for (int i = 0; i < lines.length; i++) {
//         if (!lines[i].startsWith("  @")) {
//             lines[i] = String.format("%2d %s", lineNr++, lines[i]);
//         }
//     }
//     return "Method '" + methodNode.name + "':\n" + StringUtils.join(lines, "\n") + '\n';
// }
// 
// Path: parboiled-java/src/test/java/org/parboiled/transform/AsmTestUtils.java
// public static void verifyIntegrity(String classInternalName, byte[] classCode) {
//     checkArgNotNull(classCode, "classCode");
//     ClassNode generatedClassNode = new ClassNode(ASMSettings.ASM_API);
//     ClassReader classReader = new ClassReader(classCode);
//     classReader.accept(generatedClassNode, 0);
// 
//     for (Object methodObj : generatedClassNode.methods) {
//         verifyMethodIntegrity(classInternalName, (MethodNode) methodObj);
//     }
// }


// Path: parboiled-java/src/test/java/org/parboiled/transform/ParserHierarchyTest.java
import org.parboiled.BaseParser;
import org.parboiled.Rule;
import org.parboiled.annotations.BuildParseTree;
import org.parboiled.annotations.MemoMismatches;
import org.testng.annotations.Test;
import static org.parboiled.transform.AsmTestUtils.getMethodInstructionList;
import static org.parboiled.transform.AsmTestUtils.verifyIntegrity;
import static org.testng.Assert.assertEquals;

    }

    static class Parser3 extends Parser2 {
        @Override Rule B() {
            return Sequence(super.B(), 'B', dup());
        }
        @Override Rule C() {
            return Sequence('C', super.C());
        }
        @SuppressWarnings( {"UnusedDeclaration"})
        Rule D() {
            return Sequence(super.A(), super.B(), B(), dup());
        }
    }

    static class Parser4 extends Parser1 {
        @Override Rule E() {
            return super.E();
        }
    }

    @Test
    public void verifyTestParserHierarchyExtension() throws Exception {
        ParserClassNode classNode = ParserTransformer.extendParserClass(Parser3.class);
        verifyIntegrity(classNode.name, classNode.getClassCode());

        assertEquals(getMethodInstructionList(classNode.getRuleMethods().get("$A()Lorg/parboiled/Rule;")), "" +
                "Method '$A':\n" +
                " 0     GETSTATIC org/parboiled/transform/ParserHierarchyTest$Parser1.EMPTY : Lorg/parboiled/Rule;\n" +
                " 1     ARETURN\n");
        assertEquals(getMethodInstructionList(classNode.getRuleMethods().get("A()Lorg/parboiled/Rule;")), "" +