protected void runTest(String assembly, String instr, Collection<String> disassembly, long addr,
			String ctxstr, boolean checkOneCompat, boolean checkAllExact,
			boolean checkAllSyntaxErrs, boolean checkAllSemanticErrs) {
		Address address = lang.getDefaultSpace().getAddress(addr);

		// A sanity check, first
		if (instr != null) {
			AssemblyPatternBlock ins = AssemblyPatternBlock.fromString(instr);
			if (!ins.isFullMask()) {
				throw new RuntimeException("Desired instruction bytes should be fully-defined");
			}
			final AssemblyPatternBlock ctx = (ctxstr == null ? context.getDefaultAt(address)
					: AssemblyPatternBlock.fromString(ctxstr)).fillMask();
			try {
				String disstr;
				PseudoInstruction psins = disassemble(addr, ins.getVals(), ctx.getVals());
				SleighInstructionPrototype sip = (SleighInstructionPrototype) psins.getPrototype();
				Msg.debug(this, "Expected tree: " + sip.dumpConstructorTree());
				disstr = psins.toString().trim();

				if (!disassembly.contains(disstr)) {
					throw new DisassemblyMismatchException(
						"Desired instruction bytes do not disassemble to a desired string: " +
							disassembly + "; found instead: " + disstr);
				}
			}
			catch (InsufficientBytesException | UnknownInstructionException
					| AddressOverflowException | MemoryAccessException e) {
				throw new RuntimeException("Cannot disassemble desired instruction bytes", e);
			}
		}

		Assembler assembler = Assemblers.getAssembler(lang, new AssemblySelector() {
			@Override
			public Collection<AssemblyParseResult> filterParse(
					Collection<AssemblyParseResult> parse) throws AssemblySyntaxException {
				dbgPrintTrees(parse);
				if (checkAllSyntaxErrs) {
					checkAllSyntaxErrs(parse);
				}
				return super.filterParse(parse);
			}

			@Override
			public Selection select(AssemblyResolutionResults rr, AssemblyPatternBlock ctx)
					throws AssemblySemanticException {
				if (checkOneCompat) {
					checkOneCompat(instr, rr);
				}
				if (checkAllExact) {
					checkAllExact(rr, disassembly, addr, ctxstr);
				}
				if (checkAllSemanticErrs) {
					checkAllSemanticErrs(rr);
				}
				return super.select(rr, ctx);
			}
		});

		try {
			if (ctxstr == null) {
				assembler.assembleLine(address, assembly);
			}
			else {
				SleighAssembler sas = (SleighAssembler) assembler;
				sas.assembleLine(address, assembly, AssemblyPatternBlock.fromString(ctxstr));
			}
		}
		catch (AssemblySemanticException e) {
			if (!checkAllSemanticErrs) {
				throw new AssertionError("There was an unexpected semantic error: " + e);
			}
		}
		catch (AssemblySyntaxException e) {
			if (!checkAllSyntaxErrs) {
				throw new AssertionError("There was an unexpected syntax error: " + e);
			}
		}
	}
Run a test with the given checks

@param assembly the text to assembly
@param instr an instruction pattern that must appear in the results
@param disassembly a set of acceptable disassembly texts
@param addr the address for assembly and disassembly
@param ctxstr the context for assembly and disassembly
@param checkOneCompat if {@code instr != null} check that one result matches it
@param checkAllExact if {@code disassembly != null} check that all are acceptable
@param checkAllSyntaxErrs confirm that {@code assembly} does not parse
@param checkAllSemanticErrs confirm that {@code assembly} does not assemble
@see AssemblyPatternBlock#fromString(String)
Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/app/plugin/assembler/sleigh/AssemblyTestCase.java