| // 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 |