blob: 3e097b3e7b693127dc1fbc9eab82ce803702912f [file] [log] [blame]
// Copyright (c) 2022 Google LLC.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "source/diff/lcs.h"
#include <string>
#include "gtest/gtest.h"
namespace spvtools {
namespace diff {
namespace {
using Sequence = std::vector<int>;
using LCS = LongestCommonSubsequence<Sequence>;
void VerifyMatch(const Sequence& src, const Sequence& dst,
size_t expected_match_count) {
DiffMatch src_match, dst_match;
LCS lcs(src, dst);
size_t match_count =
lcs.Get<int>([](int s, int d) { return s == d; }, &src_match, &dst_match);
EXPECT_EQ(match_count, expected_match_count);
size_t src_cur = 0;
size_t dst_cur = 0;
size_t matches_seen = 0;
while (src_cur < src.size() && dst_cur < dst.size()) {
if (src_match[src_cur] && dst_match[dst_cur]) {
EXPECT_EQ(src[src_cur], dst[dst_cur])
<< "Src: " << src_cur << " Dst: " << dst_cur;
++src_cur;
++dst_cur;
++matches_seen;
continue;
}
if (!src_match[src_cur]) {
++src_cur;
}
if (!dst_match[dst_cur]) {
++dst_cur;
}
}
EXPECT_EQ(matches_seen, expected_match_count);
}
TEST(LCSTest, EmptySequences) {
Sequence src, dst;
DiffMatch src_match, dst_match;
LCS lcs(src, dst);
size_t match_count =
lcs.Get<int>([](int s, int d) { return s == d; }, &src_match, &dst_match);
EXPECT_EQ(match_count, 0u);
EXPECT_TRUE(src_match.empty());
EXPECT_TRUE(dst_match.empty());
}
TEST(LCSTest, EmptySrc) {
Sequence src, dst = {1, 2, 3};
DiffMatch src_match, dst_match;
LCS lcs(src, dst);
size_t match_count =
lcs.Get<int>([](int s, int d) { return s == d; }, &src_match, &dst_match);
EXPECT_EQ(match_count, 0u);
EXPECT_TRUE(src_match.empty());
EXPECT_EQ(dst_match, DiffMatch(3, false));
}
TEST(LCSTest, EmptyDst) {
Sequence src = {1, 2, 3}, dst;
DiffMatch src_match, dst_match;
LCS lcs(src, dst);
size_t match_count =
lcs.Get<int>([](int s, int d) { return s == d; }, &src_match, &dst_match);
EXPECT_EQ(match_count, 0u);
EXPECT_EQ(src_match, DiffMatch(3, false));
EXPECT_TRUE(dst_match.empty());
}
TEST(LCSTest, Identical) {
Sequence src = {1, 2, 3, 4, 5, 6}, dst = {1, 2, 3, 4, 5, 6};
DiffMatch src_match, dst_match;
LCS lcs(src, dst);
size_t match_count =
lcs.Get<int>([](int s, int d) { return s == d; }, &src_match, &dst_match);
EXPECT_EQ(match_count, 6u);
EXPECT_EQ(src_match, DiffMatch(6, true));
EXPECT_EQ(dst_match, DiffMatch(6, true));
}
TEST(LCSTest, SrcPrefix) {
Sequence src = {1, 2, 3, 4}, dst = {1, 2, 3, 4, 5, 6};
DiffMatch src_match, dst_match;
LCS lcs(src, dst);
size_t match_count =
lcs.Get<int>([](int s, int d) { return s == d; }, &src_match, &dst_match);
const DiffMatch src_expect = {true, true, true, true};
const DiffMatch dst_expect = {true, true, true, true, false, false};
EXPECT_EQ(match_count, 4u);
EXPECT_EQ(src_match, src_expect);
EXPECT_EQ(dst_match, dst_expect);
}
TEST(LCSTest, DstPrefix) {
Sequence src = {1, 2, 3, 4, 5, 6}, dst = {1, 2, 3, 4, 5};
DiffMatch src_match, dst_match;
LCS lcs(src, dst);
size_t match_count =
lcs.Get<int>([](int s, int d) { return s == d; }, &src_match, &dst_match);
const DiffMatch src_expect = {true, true, true, true, true, false};
const DiffMatch dst_expect = {true, true, true, true, true};
EXPECT_EQ(match_count, 5u);
EXPECT_EQ(src_match, src_expect);
EXPECT_EQ(dst_match, dst_expect);
}
TEST(LCSTest, SrcSuffix) {
Sequence src = {3, 4, 5, 6}, dst = {1, 2, 3, 4, 5, 6};
DiffMatch src_match, dst_match;
LCS lcs(src, dst);
size_t match_count =
lcs.Get<int>([](int s, int d) { return s == d; }, &src_match, &dst_match);
const DiffMatch src_expect = {true, true, true, true};
const DiffMatch dst_expect = {false, false, true, true, true, true};
EXPECT_EQ(match_count, 4u);
EXPECT_EQ(src_match, src_expect);
EXPECT_EQ(dst_match, dst_expect);
}
TEST(LCSTest, DstSuffix) {
Sequence src = {1, 2, 3, 4, 5, 6}, dst = {5, 6};
DiffMatch src_match, dst_match;
LCS lcs(src, dst);
size_t match_count =
lcs.Get<int>([](int s, int d) { return s == d; }, &src_match, &dst_match);
const DiffMatch src_expect = {false, false, false, false, true, true};
const DiffMatch dst_expect = {true, true};
EXPECT_EQ(match_count, 2u);
EXPECT_EQ(src_match, src_expect);
EXPECT_EQ(dst_match, dst_expect);
}
TEST(LCSTest, None) {
Sequence src = {1, 3, 5, 7, 9}, dst = {2, 4, 6, 8, 10, 12};
DiffMatch src_match, dst_match;
LCS lcs(src, dst);
size_t match_count =
lcs.Get<int>([](int s, int d) { return s == d; }, &src_match, &dst_match);
EXPECT_EQ(match_count, 0u);
EXPECT_EQ(src_match, DiffMatch(5, false));
EXPECT_EQ(dst_match, DiffMatch(6, false));
}
TEST(LCSTest, NonContiguous) {
Sequence src = {1, 2, 3, 4, 5, 6, 10}, dst = {2, 4, 5, 8, 9, 10, 12};
DiffMatch src_match, dst_match;
LCS lcs(src, dst);
size_t match_count =
lcs.Get<int>([](int s, int d) { return s == d; }, &src_match, &dst_match);
const DiffMatch src_expect = {false, true, false, true, true, false, true};
const DiffMatch dst_expect = {true, true, true, false, false, true, false};
EXPECT_EQ(match_count, 4u);
EXPECT_EQ(src_match, src_expect);
EXPECT_EQ(dst_match, dst_expect);
}
TEST(LCSTest, WithDuplicates) {
Sequence src = {1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4},
dst = {1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4};
VerifyMatch(src, dst, 6);
}
TEST(LCSTest, Large) {
const std::string src_str =
"GUJwrJSlkKJXxCVIAxlVgnUyOrdyRyFtlZwWMmFhYGfkFTNnhiBmClgHyrcXMVwfrRxNUfQk"
"qaoGvCbPZHAzXsaZpXHPfJxOMCUtRDmIQpfiXKbHQbhTfPqhxBDWvmTQAqwsWTLajZYtMUnf"
"hNNCfkuAXkZsaebwEbIZOxTDZsqSMUfCMoGeKJGVSNFgLTiBMbdvchHGfFRkHKcYCDjBfIcj"
"todPnvDjzQYWBcvIfVvyBzHikrwpDORaGEZLhmyztIFCLJOqeLhOzERYmVqzlsoUzruTXTXq"
"DLTxQRakOCMRrgRzCDTXfwwfDcKMBVnxRZemjcwcEsOVxwtwdBCWJycsDcZKlvrCvZaenKlv"
"vyByDQeLdxAyBnPkIMQlMQwqjUfRLybeoaOanlbFkpTPPZdHelQrIvucTHzMpWWQTbuANwvN"
"OVhCGGoIcGNDpfIsaBexlMMdHsxMGerTngmjpdPeQQJHfvKZkdYqAzrtDohqtDsaFMxQViVQ"
"YszDVgyoSHZdOXAvXkJidojLvGZOzhRajVPhWDwKuGqdaympELxHsrXAJYufdCPwJdGJfWqq"
"yvTWpcrFHOIuCEmNLnSCDsxQGRVDwyCykBJazhApfCnrOadnafvqfVuFqEXMSrYbHTfTnzbz"
"MhISyOtMUITaurCXvanCbuOXBhHyCjOhVbxnMvhlPmZBMQgEHCghtAJVMXGPNRtszVZlPxVl"
"QIPTBnPUPejlyZGPqeICyNngdQGkvKbIoWlTLBtVhMdBeUMozNlKQTIPYBeImVcMdLafuxUf"
"TIXysmcTrUTcspOSKBxhdhLwiRnREGFWJTfUKsgGOAQeYojXdrqsGjMJfiKalyoiqrgLnlij"
"CtOapoxDGVOOBalNYGzCtBlxbvaAzxipGnJpOEbmXcpeoIsAdxspKBzBDgoPVxnuRBUwmTSr"
"CRpWhxikgUYQVCwalLUIeBPRyhhsECGCXJmGDZSCIUaBwROkigzdeVPOXhgCGBEprWtNdYfL"
"tOUYJHQXxiIJgSGmWntezJFpNQoTPbRRYAGhtYvAechvBcYWocLkYFxsDAuszvQNLXdhmAHw"
"DErcjbtCdQllnKcDADVNWVezljjLrAuyGHetINMgAvJZwOEYakihYVUbZGCsHEufluLNyNHy"
"gqtSTSFFjBHiIqQejTPWybLdpWNwZrWvIWnlzUcGNQPEYHVPCbteWknjAnWrdTBeCbHUDBoK"
"aHvDStmpNRGIjvlumiZTbdZNAzUeSFnFChCsSExwXeEfDJfjyOoSBofHzJqJErvHLNyUJTjX"
"qmtgKPpMKohUPBMhtCteQFcNEpWrUVGbibMOpvBwdiWYXNissArpSasVJFgDzrqTyGkerTMX"
"gcrzFUGFZRhNdekaJeKYPogsofJaRsUQmIRyYdkrxKeMgLPpwOfSKJOqzXDoeHljTzhOwEVy"
"krOEnACFrWhufajsMitjOWdLOHHchQDddGPzxknEgdwmZepKDvRZGCuPqzeQkjOPqUBKpKLJ"
"eKieSsRXkaqxSPGajfvPKmwFWdLByEcLgvrmteazgFjmMGrLYqRRxzUOfOCokenqHVYstBHf"
"AwsWsqPTvqsRJUfGGTaYiylZMGbQqTzINhFHvdlRQvvYKBcuAHdBeKlHSxVrSsEKbcAvnIcf"
"xzdVDdwQPHMCHeZZRpGHWvKzgTGzSTbYTeOPyKvvYWmQToTpsjAtKUJUjcEHWhmdBLDTBMHJ"
"ivBXcLGtCsumNNVFyGbVviGmqHTdyBlkneibXBesKJGOUzOtIwXCPJggqBekSzNQYkALlItk"
"cbEhbdXAIKVHYpInLwxXalKZrkrpxtfuagqMGmRJnJbFQaEoYMoqPsxZpocddPXXPyvxVkaF"
"qdKISejWDhBImnEEOPDcyWTubbfVfwUztciaFJcsPLhgYVfhqlOfoNjKbmTFptFttYuyBrUI"
"zzmZypOqrjQHTGFwlHStpIwxPtMvtsEDpsmWIgwzYgwmdpbMOnfElZMYpVIcvzSWejeJcdUB"
"QUoBRUmGQVVWvEDseuozrDjgdXFScPwwsgaUPwSzScfBNrkpmEFDSZLKfNjMqvOmUtocUkbo"
"VGFEKgGLbNruwLgXHTloWDrnqymPVAtzjWPutonIsMDPeeCmTjYWAFXcyTAlBeiJTIRkZxiM"
"kLjMnAflSNJzmZkatXkYiPEMYSmzHbLKEizHbEjQOxBDzpRHiFjhedqiyMiUMvThjaRFmwll"
"aMGgwKBIKepwyoEdnuhtzJzboiNEAFKiqiWxxmkRFRoTiFWXLPAWLuzSCrajgkQhDxAQDqyM"
"VwZlhZicQLEDYYisEalesDWZAYzcvENuHUwRutIsGgsdoYwOZiURhcgdbTGWBNqhrFjvTQCj"
"VlTPNlRdRLaaqzUBBwbdtyXFkCBUYYMbmRrkFxfxbCqkgZNGyHPKLkOPnezfVTRmRQgCgHbx"
"wcZlInVOwmFePnSIbThMJosimzkhfuiqYEpwHQiemqsSDNNdbNhBLzbsPZBJZujSHJGtYKGb"
"HaAYGJZxBumsKUrATwPuqXFLfwNyImLQbchBKiJAYRZhkcrKCHXBEGYyBhBGvSqvabcRUrfq"
"AbPiMzjHAehGYjDEmxAnYLyoSFdeWVrfJUCuYZPluhXEBuyUpKaRXDKXeiCvGidpvATwMbcz"
"DZpzxrhTZYyrFORFQWTbPLCBjMKMhlRMFEiarDgGPttjmkrQVlujztMSkxXffXFNqLWOLThI"
"KBoyMHoFTEPCdUAZjLTifAdjjUehyDLEGKlRTFoLpjalziRSUjZfRYbNzhiHgTHowMMkKTwE"
"ZgnqiirMtnNpaBJqhcIVrWXPpcPWZfRpsPstHleFJDZYAsxYhOREVbFtebXTZRAIjGgWeoiN"
"qPLCCAVadqmUrjOcqIbdCTpcDRWuDVbHrZOQRPhqbyvOWwxAWJphjLiDgoAybcjzgfVktPlj"
"kNBCjelpuQfnYsiTgPpCNKYtOrxGaLEEtAuLdGdDsONHNhSn";
const std::string dst_str =
"KzitfifORCbGhfNEbnbObUdFLLaAsLOpMkOeKupjCoatzqfHBkNJfSgqSMYouswfNMnoQngK"
"jWwyPKmEnoZWyPBUdQRmKUNudUclueKXKQefUdXWUyyqtumzsFKznrLVLwfvPZpLChNYrrHK"
"AtpfOuVHiUKyeRCrktJAhkyFKmPWrASEMvBLNOzuGlvinZjvZUUXazNEkyMPiOLdqXvCIroC"
"MeWsvjHShlLhDwLZrVlpYBnDJmILcsNFDSoaLWOKNNkNGBgNBvVjPCJXAuKfsrKZhYcdEpxK"
"UihiRkYvMiLyOUvaqBMklLDwEhvQBfCXHSRoqsLsSCzLZQhIYMhBapvHaPbDoRrHoJXZsNXc"
"rxZYCrOMIzYcVPwDCFiHBFnPNTTeAeKEMGeVUeCaAeuWZmngyPWlQBcgWumSUIfbhjVYdnpV"
"hRSJXrIoFZubBXfNOMhilAkVPixrhILZKgDoFTvytPFPfBLMnbhSOBmLWCbJsLQxrCrMAlOw"
"RmfSQyGhrjhzYVqFSBHeoQBagFwyxIjcHFZngntpVHbSwqhwHeMnWSsISPljTxSNXfCxLebW"
"GhMdlphtJbdvhEcjNpwPCFqhdquxCyOxkjsDUPNgjpDcpIMhMwMclNhfESTrroJaoyeGQclV"
"gonnhuQRmXcBwcsWeLqjNngZOlyMyfeQBwnwMVJEvGqknDyzSApniRTPgJpFoDkJJhXQFuFB"
"VqhuEPMRGCeTDOSEFmXeIHOnDxaJacvnmORwVpmrRhGjDpUCkuODNPdZMdupYExDEDnDLdNF"
"iObKBaVWpGVMKdgNLgsNxcpypBPPKKoaajeSGPZQJWSOKrkLjiFexYVmUGxJnbTNsCXXLfZp"
"jfxQAEVYvqKehBzMsVHVGWmTshWFAoCNDkNppzzjHBZWckrzSTANICioCJSpLwPwQvtXVxst"
"nTRBAboPFREEUFazibpFesCsjzUOnECwoPCOFiwGORlIZVLpUkJyhYXCENmzTBLVigOFuCWO"
"IiXBYmiMtsxnUdoqSTTGyEFFrQsNAjcDdOKDtHwlANWoUVwiJCMCQFILdGqzEePuSXFbOEOz"
"dLlEnTJbKRSTfAFToOZNtDXTfFgvQiefAKbSUWUXFcpCjRYCBNXCCcLMjjuUDXErpiNsRuIx"
"mgHsrObTEXcnmjdqxTGhTjTeYizNnkrJRhNQIqDXmZMwArBccnixpcuiGOOexjgkpcEyGAnz"
"UbgiBfflTUyJfZeFFLrZVueFkSRosebnnwAnakIrywTGByhQKWvmNQJsWQezqLhHQzXnEpeD"
"rFRTSQSpVxPzSeEzfWYzfpcenxsUyzOMLxhNEhfcuprDtqubsXehuqKqZlLQeSclvoGjuKJK"
"XoWrazsgjXXnkWHdqFESZdMGDYldyYdbpSZcgBPgEKLWZHfBirNPLUadmajYkiEzmGuWGELB"
"WLiSrMdaGSbptKmgYVqMGcQaaATStiZYteGAPxSEBHuAzzjlRHYsrdDkaGNXmzRGoalJMiCC"
"GMtWSDMhgvRSEgKnywbRgnqWXFlwrhXbbvcgLGtWSuKQBiqIlWkfPMozOTWgVoLHavDJGRYI"
"YerrmZnTMtuuxmZALWakfzUbksTwoetqkOiRPGqGZepcVXHoZyOaaaijjZWQLlIhYwiQNbfc"
"KCwhhFaMQBoaCnOecJEdKzdsMPFEYQuJNPYiiNtsYxaWBRuWjlLqGokHMNtyTQfSJKbgGdol"
"fWlOZdupouQMfUWXIYHzyJHefMDnqxxasDxtgArvDqtwjDBaVEMACPkLFpiDOoKCHqkWVizh"
"lKqbOHpsPKkhjRQRNGYRYEfxtBjYvlCvHBNUwVuIwDJYMqHxEFtwdLqYWvjdOfQmNiviDfUq"
"pbucbNwjNQfMYgwUuPnQWIPOlqHcbjtuDXvTzLtkdBQanJbrmLSyFqSapZCSPMDOrxWVYzyO"
"lwDTTJFmKxoyfPunadkHcrcSQaQsAbrQtbhqwSTXGTPURYTCbNozjAVwbmcyVxIbZudBZWYm"
"rnSDyelGCRRWYtrUxvOVWlTLHHdYuAmVMGnGbHscbjmjmAzmYLaCxNNwhmMYdExKvySxuYpE"
"rVGwfqMngBCHnZodotNaNJZiNRFWubuPDfiywXPiyVWoQMeOlSuWmpilLTIFOvfpjmJTgrWa"
"dgoxYeyPyOaglOvZVGdFOBSeqEcGXBwjoeUAXqkpvOxEpSXhmklKZydTvRVYVvfQdRNNDkCT"
"dLNfcZCFQbZORdcDOhwotoyccrSbWvlqYMoiAYeEpDzZTvkamapzZMmCpEutZFCcHBWGIIkr"
"urwDNHrobaErPpclyEegLJDtkfUWSNWZosWSbBGAHIvJsFNUlJXbnkSVycLkOVQVcNcUtiBy"
"djLDIFsycbPBEWaMvCbntNtJlOeCttvXypGnHAQFnFSiXFWWqonWuVIKmVPpKXuJtFguXCWC"
"rNExYYvxLGEmuZJLJDjHgjlQyOzeieCpizJxkrdqKCgomyEkvsyVYSsLeyLvOZQrrgEJgRFK"
"CjYtoOfluNrLdRMTRkQXmAiMRFwloYECpXCReAMxOkNiwCtutsrqWoMHsrogRqPoUCueonvW"
"MTwmkAkajfGJkhnQidwpwIMEttQkzIMOPvvyWZHpqkMHWlNTeSKibfRfwDyxveKENZhtlPwP"
"dfAjwegjRcavtFnkkTNVYdCdCrgdUvzsIcqmUjwGmVvuuQvjVrWWIDBmAzQtiZPYvCOEWjce"
"rWzeqVKeiYTJBOedmQCVidOgUIEjfRnbGvUbctYxfRybJkdmeAkLZQMRMGPOnsPbFswXAoCK"
"IxWGwohoPpEJxslbqHFKSwknxTmrDCITRZWEDkGQeucPxHBdYkduwbYhKnoxCKhgjBFiFawC"
"QtgTDldTQmlOsBiGLquMjuecAbrUJJvNtXbFNGjWxaZPimSRXUJWgRbydpsczOqSFIeEtuKA"
"ZpRhmLtPdVNKdSDQZeeImUFmUwXApRTUNHItyvFyJtNtn";
Sequence src;
Sequence dst;
src.reserve(src_str.length());
dst.reserve(dst_str.length());
for (char c : src_str) {
src.push_back(c);
}
for (char c : dst_str) {
dst.push_back(c);
}
VerifyMatch(src, dst, 723);
}
} // namespace
} // namespace diff
} // namespace spvtools