@Test
	public void testMergeOverlayLabels() throws Exception {
		mtf.initialize("NotepadMergeListingTest", new ProgramModifierListener() {
			@Override
			public void modifyLatest(ProgramDB program) {
				// P1 program
				try {
					Memory memory = program.getMemory();
					memory.createInitializedBlock("Foo", addr(program, "0x01000000"), 0x200L,
						(byte) 0x0, null, true);

					SymbolTable st = program.getSymbolTable();
					Namespace globalNamespace = program.getGlobalNamespace();
					st.createLabel(addr(program, "Foo::0x01000030"), "Sample0030", globalNamespace,
						SourceType.USER_DEFINED);
					st.createLabel(addr(program, "Foo::0x0100007f"), "Sample007f", globalNamespace,
						SourceType.USER_DEFINED);
					st.createLabel(addr(program, "Foo::0x0100017f"), "Sample017f", globalNamespace,
						SourceType.USER_DEFINED);
					st.createLabel(addr(program, "Foo::0x01000100"), "Sample0100", globalNamespace,
						SourceType.USER_DEFINED);
				}
				catch (Exception e) {
					Assert.fail(e.getMessage());
				}
			}

			@Override
			public void modifyPrivate(ProgramDB program) {
				// P2 program
				try {
					Memory memory = program.getMemory();
					memory.createInitializedBlock("Foo", addr(program, "0x01000000"), 0x200L,
						(byte) 0x0, null, true);

					SymbolTable st = program.getSymbolTable();
					Namespace globalNamespace = program.getGlobalNamespace();
					st.createLabel(addr(program, "Foo::0x01000080"), "Other0080", globalNamespace,
						SourceType.USER_DEFINED);
					st.createLabel(addr(program, "Foo::0x01000180"), "Other0180", globalNamespace,
						SourceType.USER_DEFINED);
					st.createLabel(addr(program, "Foo::0x010001ff"), "Other01ff", globalNamespace,
						SourceType.USER_DEFINED);
					st.createLabel(addr(program, "Foo::0x01000100"), "Other0100", globalNamespace,
						SourceType.USER_DEFINED);
				}
				catch (Exception e) {
					Assert.fail(e.getMessage());
				}
			}
		});

		p1 = mtf.getResultProgram();
		p2 = mtf.getPrivateProgram();

		int txId = p1.startTransaction("Merge into Program 1");
		boolean commit = false;
		try {
			programMerge = new ProgramMergeManager(p1, p2);

			programMerge.setDiffFilter(new ProgramDiffFilter(
				ProgramDiffFilter.SYMBOL_DIFFS | ProgramDiffFilter.FUNCTION_DIFFS));
			programMerge.setMergeFilter(
				new ProgramMergeFilter(ProgramMergeFilter.SYMBOLS, ProgramMergeFilter.MERGE));
			AddressSet expectedDiffs = new AddressSet();
			expectedDiffs.addRange(addr(p1, "Foo::0x01000030"), addr(p1, "Foo::0x01000030"));
			expectedDiffs.addRange(addr(p1, "Foo::0x0100007f"), addr(p1, "Foo::0x0100007f"));
			expectedDiffs.addRange(addr(p1, "Foo::0x01000080"), addr(p1, "Foo::0x01000080"));
			expectedDiffs.addRange(addr(p1, "Foo::0x01000100"), addr(p1, "Foo::0x01000100"));
			expectedDiffs.addRange(addr(p1, "Foo::0x0100017f"), addr(p1, "Foo::0x0100017f"));
			expectedDiffs.addRange(addr(p1, "Foo::0x01000180"), addr(p1, "Foo::0x01000180"));
			expectedDiffs.addRange(addr(p1, "Foo::0x010001ff"), addr(p1, "Foo::0x010001ff"));
			assertEquals(expectedDiffs, programMerge.getFilteredDifferences());

			AddressSet mergeSet = new AddressSet();
			mergeSet.addRange(addr(p1, "Foo::0x01000030"), addr(p1, "Foo::0x01000030"));
			mergeSet.addRange(addr(p1, "Foo::0x0100007f"), addr(p1, "Foo::0x0100007f"));
			mergeSet.addRange(addr(p1, "Foo::0x01000080"), addr(p1, "Foo::0x01000080"));
			mergeSet.addRange(addr(p1, "Foo::0x01000100"), addr(p1, "Foo::0x01000100"));
			mergeSet.addRange(addr(p1, "Foo::0x0100017f"), addr(p1, "Foo::0x0100017f"));
			mergeSet.addRange(addr(p1, "Foo::0x01000180"), addr(p1, "Foo::0x01000180"));
			mergeSet.addRange(addr(p1, "Foo::0x010001ff"), addr(p1, "Foo::0x010001ff"));
			programMerge.merge(mergeSet, TaskMonitor.DUMMY);

			AddressSet newDiffs = new AddressSet();
			newDiffs.addRange(addr(p1, "Foo::0x01000030"), addr(p1, "Foo::0x01000030"));
			newDiffs.addRange(addr(p1, "Foo::0x0100007f"), addr(p1, "Foo::0x0100007f"));
			newDiffs.addRange(addr(p1, "Foo::0x01000100"), addr(p1, "Foo::0x01000100"));
			newDiffs.addRange(addr(p1, "Foo::0x0100017f"), addr(p1, "Foo::0x0100017f"));
			assertEquals(newDiffs, programMerge.getFilteredDifferences());

			SymbolTable st = p1.getSymbolTable();
			Symbol[] symbols;
			symbols = st.getSymbols(addr(p1, "Foo::0x01000030"));
			assertEquals(1, symbols.length);
			assertEquals("Sample0030", symbols[0].getName(true));

			symbols = st.getSymbols(addr(p1, "Foo::0x0100007f"));
			assertEquals(1, symbols.length);
			assertEquals("Sample007f", symbols[0].getName(true));

			symbols = st.getSymbols(addr(p1, "Foo::0x01000080"));
			assertEquals(1, symbols.length);
			assertEquals("Other0080", symbols[0].getName(true));

			symbols = st.getSymbols(addr(p1, "Foo::0x01000100"));
			assertEquals(2, symbols.length);
			Comparator<Symbol> c = SymbolUtilities.getSymbolNameComparator();
			Arrays.sort(symbols, c);
			assertEquals("Other0100", symbols[0].getName(true));
			assertEquals("Sample0100", symbols[1].getName(true));

			symbols = st.getSymbols(addr(p1, "Foo::0x0100017f"));
			assertEquals(1, symbols.length);
			assertEquals("Sample017f", symbols[0].getName(true));

			symbols = st.getSymbols(addr(p1, "Foo::0x01000180"));
			assertEquals(1, symbols.length);
			assertEquals("Other0180", symbols[0].getName(true));

			symbols = st.getSymbols(addr(p1, "Foo::0x010001ff"));
			assertEquals(1, symbols.length);
			assertEquals("Other01ff", symbols[0].getName(true));
			commit = true;
		}
		finally {
			p1.endTransaction(txId, commit);
		}

		ProgramDiff latestProgramDiff = new ProgramDiff(p1, mtf.getLatestProgram());
		AddressSet latestAddrSet = new AddressSet();
		latestAddrSet.addRange(addr(p1, "Foo::0x01000080"), addr(p1, "Foo::0x01000080"));
		latestAddrSet.addRange(addr(p1, "Foo::0x01000180"), addr(p1, "Foo::0x01000180"));
		latestAddrSet.addRange(addr(p1, "Foo::0x01000100"), addr(p1, "Foo::0x01000100"));
		latestAddrSet.addRange(addr(p1, "Foo::0x010001ff"), addr(p1, "Foo::0x010001ff"));
		latestProgramDiff.setFilter(new ProgramDiffFilter(ProgramDiffFilter.ALL_DIFFS));
		assertEquals(latestAddrSet,
			latestProgramDiff.getDifferences(latestProgramDiff.getFilter(), null));

		ProgramDiff myProgramDiff = new ProgramDiff(p1, mtf.getPrivateProgram());
		AddressSet myAddrSet = new AddressSet();
		myAddrSet.addRange(addr(p1, "Foo::0x01000030"), addr(p1, "Foo::0x01000030"));
		myAddrSet.addRange(addr(p1, "Foo::0x0100007f"), addr(p1, "Foo::0x0100007f"));
		myAddrSet.addRange(addr(p1, "Foo::0x01000100"), addr(p1, "Foo::0x01000100"));
		myAddrSet.addRange(addr(p1, "Foo::0x0100017f"), addr(p1, "Foo::0x0100017f"));
		myProgramDiff.setFilter(new ProgramDiffFilter(ProgramDiffFilter.ALL_DIFFS));
		assertEquals(myAddrSet, myProgramDiff.getDifferences(myProgramDiff.getFilter(), null));
	}
<CODE>ProgramMerge2Test</CODE> tests the <CODE>ProgramMerge</CODE> class
to verify it correctly merges various types of program differences.
The tests modify copies of the same program to cause differences
between these two programs, which can then be merged.
Ghidra/Features/Base/src/test.slow/java/ghidra/program/util/ProgramMerge2Test.java