diff --git a/test_vx.py b/test_vx.py deleted file mode 100644 index 3b4fd96..0000000 --- a/test_vx.py +++ /dev/null @@ -1,260 +0,0 @@ -import os - -import twitfix,twExtract,vxApi -import cache -from flask.testing import FlaskClient -client = FlaskClient(twitfix.app) - -# autogenerated from testgen.py -testTextTweet="https://twitter.com/jack/status/20" -testVideoTweet="https://twitter.com/pdxdylan/status/1540398733669666818" -testMediaTweet="https://twitter.com/pdxdylan/status/1534672932106035200" -testMultiMediaTweet="https://twitter.com/pdxdylan/status/1532006436703715331" -testQRTTweet="https://twitter.com/pdxdylan/status/1611477137319514129" -testQrtCeptionTweet="https://twitter.com/CatherineShu/status/585253766271672320" -testQrtVideoTweet="https://twitter.com/pdxdylan/status/1674561759422578690" -testNSFWTweet="https://twitter.com/kuyacoy/status/1581185279376838657" -testPollTweet="https://twitter.com/norm/status/651169346518056960" - -testTextTweet_compare={'text': 'just setting up my twttr', 'date': 'Tue Mar 21 20:50:14 +0000 2006', 'tweetURL': 'https://twitter.com/jack/status/20', 'tweetID': '20', 'conversationID': '20', 'mediaURLs': [], 'media_extended': [], 'possibly_sensitive': False, 'hashtags': [], 'qrtURL': None, 'allSameType': False, 'hasMedia': False, 'combinedMediaUrl': None, 'pollData': None, 'date_epoch': 1142974214} -testVideoTweet_compare={'text': 'TikTok embeds on Discord/Telegram bait you with a fake play button, but to see the actual video you have to go to their website.\nAs a request from a friend, I made it so that if you add "vx" before "tiktok" on any link, it fixes that. https://t.co/QYpiVXUIrW', 'date': 'Fri Jun 24 18:17:31 +0000 2022', 'tweetURL': 'https://twitter.com/pdxdylan/status/1540398733669666818', 'tweetID': '1540398733669666818', 'conversationID': '1540398733669666818', 'mediaURLs': ['https://video.twimg.com/ext_tw_video/1540396699037929472/pu/vid/762x528/YxbXbT3X7vq4LWfC.mp4?tag=12'], 'media_extended': [{'url': 'https://video.twimg.com/ext_tw_video/1540396699037929472/pu/vid/762x528/YxbXbT3X7vq4LWfC.mp4?tag=12', 'type': 'video', 'size': {'width': 762, 'height': 528}, 'duration_millis': 13650, 'thumbnail_url': 'https://pbs.twimg.com/ext_tw_video_thumb/1540396699037929472/pu/img/l187Z6B9AHHxUKPV.jpg', 'altText': None}], 'possibly_sensitive': False, 'hashtags': [], 'qrtURL': None, 'allSameType': False, 'hasMedia': True, 'combinedMediaUrl': None, 'pollData': None, 'date_epoch': 1656094651} -testMediaTweet_compare={'text': 'oh. https://t.co/HgLAbiXw2E', 'date': 'Wed Jun 08 23:05:14 +0000 2022', 'tweetURL': 'https://twitter.com/pdxdylan/status/1534672932106035200', 'tweetID': '1534672932106035200', 'conversationID': '1534672673422381057', 'mediaURLs': ['https://pbs.twimg.com/media/FUxAt5LWUAMol0N.png'], 'media_extended': [{'url': 'https://pbs.twimg.com/media/FUxAt5LWUAMol0N.png', 'altText': None, 'type': 'image', 'size': {'width': 927, 'height': 534}, 'thumbnail_url': 'https://pbs.twimg.com/media/FUxAt5LWUAMol0N.png'}], 'possibly_sensitive': False, 'hashtags': [], 'qrtURL': None, 'allSameType': False, 'hasMedia': True, 'combinedMediaUrl': None, 'pollData': None, 'date_epoch': 1654729514} -testMultiMediaTweet_compare={'text': 'Released #Retro64 1.0.9. Besides a lot of internal bug-fixes, this adds quicksand blocks, fixes the rendering for the castle stairs block, and adds a new model, Sonic! \nhttps://github.com/Retro64Mod/Retro64Mod/releases/tag/1.18.2-1.0.9 https://t.co/CWZaw4hzyg', 'date': 'Wed Jun 01 14:29:32 +0000 2022', 'tweetURL': 'https://twitter.com/pdxdylan/status/1532006436703715331', 'tweetID': '1532006436703715331', 'conversationID': '1532006436703715331', 'mediaURLs': ['https://pbs.twimg.com/media/FULF9oxXwAMDI-C.png', 'https://pbs.twimg.com/media/FULGaHkWYAIBV5U.png', 'https://pbs.twimg.com/media/FULGiZnWQAMBRWl.png'], 'media_extended': [{'url': 'https://pbs.twimg.com/media/FULF9oxXwAMDI-C.png', 'altText': None, 'type': 'image', 'size': {'width': 507, 'height': 507}, 'thumbnail_url': 'https://pbs.twimg.com/media/FULF9oxXwAMDI-C.png'}, {'url': 'https://pbs.twimg.com/media/FULGaHkWYAIBV5U.png', 'altText': None, 'type': 'image', 'size': {'width': 396, 'height': 431}, 'thumbnail_url': 'https://pbs.twimg.com/media/FULGaHkWYAIBV5U.png'}, {'url': 'https://pbs.twimg.com/media/FULGiZnWQAMBRWl.png', 'altText': None, 'type': 'image', 'size': {'width': 399, 'height': 341}, 'thumbnail_url': 'https://pbs.twimg.com/media/FULGiZnWQAMBRWl.png'}], 'possibly_sensitive': False, 'hashtags': ['Retro64'], 'qrtURL': None, 'allSameType': True, 'hasMedia': True, 'combinedMediaUrl': 'https://vxtwitter.com/rendercombined.jpg?imgs=https://pbs.twimg.com/media/FULF9oxXwAMDI-C.png,https://pbs.twimg.com/media/FULGaHkWYAIBV5U.png,https://pbs.twimg.com/media/FULGiZnWQAMBRWl.png', 'pollData': None, 'date_epoch': 1654093772} -testQRTTweet_compare={'text': "vxTwitter has gotten a *ton* of usage recently, so I'd appreciate a donation to keep things running!\n", 'date': 'Fri Jan 06 21:37:43 +0000 2023', 'tweetURL': 'https://twitter.com/pdxdylan/status/1611477137319514129', 'tweetID': '1611477137319514129', 'conversationID': '1611476665821003776', 'mediaURLs': [], 'media_extended': [], 'possibly_sensitive': False, 'hashtags': [], 'qrtURL': 'https://twitter.com/i/status/1518309187515781125', 'allSameType': False, 'hasMedia': False, 'combinedMediaUrl': None, 'pollData': None, 'date_epoch': 1673041063} -testQrtCeptionTweet_compare={'text': 'Testing retweetception ', 'date': 'Tue Apr 07 01:32:26 +0000 2015', 'tweetURL': 'https://twitter.com/CatherineShu/status/585253766271672320', 'tweetID': '585253766271672320', 'conversationID': '585253766271672320', 'mediaURLs': [], 'media_extended': [], 'possibly_sensitive': False, 'hashtags': [], 'qrtURL': 'https://twitter.com/i/status/585253161260216320', 'allSameType': False, 'hasMedia': False, 'combinedMediaUrl': None, 'pollData': None, 'date_epoch': 1428370346} -testQrtVideoTweet_compare={'text': 'good', 'date': 'Thu Jun 29 23:33:29 +0000 2023', 'tweetURL': 'https://twitter.com/pdxdylan/status/1674561759422578690', 'tweetID': '1674561759422578690', 'conversationID': '1674561759422578690', 'mediaURLs': [], 'media_extended': [], 'possibly_sensitive': False, 'hashtags': [], 'qrtURL': 'https://twitter.com/i/status/1674197531301904388', 'allSameType': False, 'hasMedia': False, 'combinedMediaUrl': None, 'pollData': None, 'date_epoch': 1688081609} -testNSFWTweet_compare={'text': "ngl, I'm scared on finding out the cute Sprigatito's final evolution..\n\nso i had a bot generate it for me.... and I'm forever scarred https://t.co/itMay87vcS", 'date': 'Sat Oct 15 07:28:42 +0000 2022', 'tweetURL': 'https://twitter.com/kuyacoy/status/1581185279376838657', 'tweetID': '1581185279376838657', 'conversationID': '1581185279376838657', 'mediaURLs': ['https://pbs.twimg.com/media/FfF_gKwXgAIpnpD.jpg'], 'media_extended': [{'url': 'https://pbs.twimg.com/media/FfF_gKwXgAIpnpD.jpg', 'altText': None, 'type': 'image', 'size': {'width': 760, 'height': 926}, 'thumbnail_url': 'https://pbs.twimg.com/media/FfF_gKwXgAIpnpD.jpg'}], 'possibly_sensitive': False, 'hashtags': [], 'qrtURL': None, 'allSameType': False, 'hasMedia': True, 'combinedMediaUrl': None, 'pollData': None, 'date_epoch': 1665818922} -testPollTweet_compare={'text': 'I know when that hotline bling, that can only:', 'date': 'Mon Oct 05 22:57:25 +0000 2015', 'tweetURL': 'https://twitter.com/norm/status/651169346518056960', 'tweetID': '651169346518056960', 'conversationID': '651169346518056960', 'mediaURLs': [], 'media_extended': [], 'possibly_sensitive': False, 'hashtags': [], 'qrtURL': None, 'allSameType': False, 'hasMedia': False, 'combinedMediaUrl': None, 'pollData': {'options': [{'name': 'Mean one thing', 'votes': 124875, 'percent': 78.82}, {'name': 'Mean multiple things', 'votes': 33554, 'percent': 21.18}]}, 'date_epoch': 1444085845} - -testUser="https://twitter.com/jack" -testUserID = "https://twitter.com/i/user/12" -testUserWeirdURLs=["https://twitter.com/jack?lang=en","https://twitter.com/jack/with_replies","https://twitter.com/jack/media","https://twitter.com/jack/likes","https://twitter.com/jack/with_replies?lang=en","https://twitter.com/jack/media?lang=en","https://twitter.com/jack/likes?lang=en","https://twitter.com/jack/"] -testTextTweet="https://twitter.com/jack/status/20" - -tokens=os.getenv("VXTWITTER_WORKAROUND_TOKENS",None).split(',') - -def compareDict(original,compare): - for key in original: - assert key in compare - if type(compare[key]) is not dict: - if (key == 'verified' or key== 'time') and compare[key]!=original[key]: - continue # does not match as test data was from before verification changes - assert compare[key]==original[key] - else: - compareDict(original[key],compare[key]) - -## Specific API tests ## -def test_twextract_syndicationAPI(): - tweet = twExtract.extractStatus_syndication(testMediaTweet,workaroundTokens=tokens) - assert tweet["full_text"]==testMediaTweet_compare['text'] - -def test_twextract_extractStatusV2Anon(): - tweet = twExtract.extractStatusV2AnonLegacy(testTextTweet,None) - assert tweet["full_text"]==testTextTweet_compare['text'] - tweet = twExtract.extractStatusV2AnonLegacy(testVideoTweet,None) - assert tweet["full_text"]==testVideoTweet_compare['text'] - tweet = twExtract.extractStatusV2AnonLegacy(testMediaTweet,None) - assert tweet["full_text"]==testMediaTweet_compare['text'] - tweet = twExtract.extractStatusV2AnonLegacy(testMultiMediaTweet,None) - assert tweet["full_text"][:94]==testMultiMediaTweet_compare['text'][:94] - - -def test_twextract_v2API(): - tweet = twExtract.extractStatusV2Legacy(testMediaTweet,workaroundTokens=tokens) - assert tweet["full_text"]==testMediaTweet_compare['text'] - -## Tweet retrieve tests ## -def test_twextract_textTweetExtract(): - tweet = twExtract.extractStatus(testTextTweet,workaroundTokens=tokens) - assert tweet["full_text"]==testTextTweet_compare['text'] - assert tweet["user"]["screen_name"]=="jack" - assert 'extended_entities' not in tweet - -def test_twextract_extractV2(): # remove this when v2 is default - tweet = twExtract.extractStatusV2(testTextTweet,workaroundTokens=tokens) - -def test_twextract_UserExtract(): - user = twExtract.extractUser(testUser,workaroundTokens=tokens) - assert user["screen_name"]=="jack" - assert user["id"]==12 - assert user["created_at"] == "Tue Mar 21 20:50:14 +0000 2006" - -def test_twextract_UserExtractID(): - user = twExtract.extractUser(testUserID,workaroundTokens=tokens) - assert user["screen_name"]=="jack" - assert user["id"]==12 - assert user["created_at"] == "Tue Mar 21 20:50:14 +0000 2006" - -def test_twextract_UserExtractWeirdURLs(): - for url in testUserWeirdURLs: - user = twExtract.extractUser(url,workaroundTokens=tokens) - assert user["screen_name"]=="jack" - assert user["id"]==12 - assert user["created_at"] == "Tue Mar 21 20:50:14 +0000 2006" - -def test_twextract_videoTweetExtract(): - tweet = twExtract.extractStatus(testVideoTweet,workaroundTokens=tokens) - assert tweet["full_text"]==testVideoTweet_compare['text'] - assert 'extended_entities' in tweet - assert len(tweet['extended_entities']["media"])==1 - video = tweet['extended_entities']["media"][0] - assert video["media_url_https"]==testVideoTweet_compare['media_extended'][0]['thumbnail_url'] - assert video["type"]=="video" - - -def test_twextract_mediaTweetExtract(): - tweet = twExtract.extractStatus(testMediaTweet,workaroundTokens=tokens) - assert tweet["full_text"]==testMediaTweet_compare['text'] - assert 'extended_entities' in tweet - assert len(tweet['extended_entities']["media"])==1 - video = tweet['extended_entities']["media"][0] - - assert video["media_url_https"]==testMediaTweet_compare['media_extended'][0]['thumbnail_url'] - assert video["type"]=="photo" - - -def test_twextract_multimediaTweetExtract(): - tweet = twExtract.extractStatus(testMultiMediaTweet,workaroundTokens=tokens) - assert tweet["full_text"][:94]==testMultiMediaTweet_compare['text'][:94] - assert 'extended_entities' in tweet - assert len(tweet['extended_entities']["media"])==3 - video = tweet['extended_entities']["media"][0] - assert video["media_url_https"]==testMultiMediaTweet_compare["mediaURLs"][0] - assert video["type"]=="photo" - video = tweet['extended_entities']["media"][1] - assert video["media_url_https"]==testMultiMediaTweet_compare["mediaURLs"][1] - assert video["type"]=="photo" - -def test_twextract_pollTweetExtract(): # basic check if poll data exists - tweet = twExtract.extractStatus("https://twitter.com/norm/status/651169346518056960",workaroundTokens=tokens) - assert 'card' in tweet - assert tweet['card']['name']=="poll2choice_text_only" - -def test_twextract_NSFW_TweetExtract(): - tweet = twExtract.extractStatus(testNSFWTweet,workaroundTokens=tokens) # For now just test that there's no error - -def getVNFFromLink(link): - return twitfix.getTweetData(link) - -## VNF conversion test ## -def test_textTweetVNF(): - vnf = getVNFFromLink(testTextTweet) - compareDict(testTextTweet_compare,vnf) - -def test_videoTweetVNF(): - vnf = getVNFFromLink(testVideoTweet) - - compareDict(testVideoTweet_compare,vnf) - -def test_mediaTweetVNF(): - vnf = getVNFFromLink(testMediaTweet) - compareDict(testMediaTweet_compare,vnf) - -def test_multimediaTweetVNF(): - vnf = getVNFFromLink(testMultiMediaTweet) - compareDict(testMultiMediaTweet_compare,vnf) - -def test_pollTweetVNF(): - vnf = getVNFFromLink(testPollTweet) - compareDict(testPollTweet_compare,vnf) - -def test_qrtTweet(): - cache.clearCache() - # this is an incredibly lazy test, todo: improve it in the future - resp = client.get(testQRTTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"}) - assert resp.status_code==200 - assert testQRTTweet_compare['text'][:10] in str(resp.data) - # test qrt-ception - resp = client.get(testQrtCeptionTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"}) # get top level tweet - assert resp.status_code==200 - assert "Please retweet this to spread awareness for retweets" in str(resp.data) - qtd_tweet=cache.getVnfFromLinkCache("https://twitter.com/EliLanger/status/585253161260216320") # check that the quoted tweet for the top level tweet is cached - assert qtd_tweet is not None - assert qtd_tweet["qrtURL"] is not None # check that the quoted tweet for the top level tweet has a qrtURL - assert cache.getVnfFromLinkCache("https://twitter.com/EliLanger/status/313143446842007553") is None # check that the bottom level tweet has NOT been cached - resp = client.get("/EliLanger/status/585253161260216320",headers={"User-Agent":"test"}) # get mid level tweet - assert resp.status_code==200 - assert cache.getVnfFromLinkCache("https://twitter.com/EliLanger/status/313143446842007553") is not None # check that the bottom level tweet has been cached now - -def test_qrtVideoTweet(): - cache.clearCache() - # this is an incredibly lazy test, todo: improve it in the future - resp = client.get(testQrtVideoTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"}) - assert resp.status_code==200 - qtd_tweet=cache.getVnfFromLinkCache("https://twitter.com/i/status/1674197531301904388") - vurl = qtd_tweet["mediaURLs"][0] - assert f"twitter:player:stream\" content=\"{vurl}" in str(resp.data) - -## Test adding to cache ; cache should be empty ## -def test_addToCache(): - cache.clearCache() - twitfix.getTweetData(testTextTweet) - twitfix.getTweetData(testVideoTweet) - twitfix.getTweetData(testMediaTweet) - twitfix.getTweetData(testMultiMediaTweet) - #retrieve - compareDict(testTextTweet_compare,cache.getVnfFromLinkCache(testTextTweet)) - compareDict(testVideoTweet_compare,cache.getVnfFromLinkCache(testVideoTweet)) - compareDict(testMediaTweet_compare,cache.getVnfFromLinkCache(testMediaTweet)) - compareDict(testMultiMediaTweet_compare,cache.getVnfFromLinkCache(testMultiMediaTweet)) - cache.clearCache() - -def test_embedFromScratch(): - cache.clearCache() - client.get(testTextTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"}) - client.get(testVideoTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"}) - client.get(testMediaTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"}) - client.get(testMultiMediaTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"}) - -def test_embedFromCache(): - cache.clearCache() - twitfix.getTweetData(testTextTweet) - twitfix.getTweetData(testVideoTweet) - twitfix.getTweetData(testMediaTweet) - twitfix.getTweetData(testMultiMediaTweet) - #embed time - resp = client.get(testTextTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"}) - assert resp.status_code==200 - resp = client.get(testVideoTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"}) - assert resp.status_code==200 - resp = client.get(testMediaTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"}) - assert resp.status_code==200 - resp = client.get(testMultiMediaTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"}) - assert resp.status_code==200 - -def test_embedSuggestive(): - resp = client.get(testNSFWTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"}) - assert resp.status_code==200 - assert "so i had a bot generate it for me" in str(resp.data) - assert "FfF_gKwXgAIpnpD" in str(resp.data) - -def test_veryLongEmbed(): - cache.clearCache() - cache.setCache({'https://twitter.com/TEST/status/1234': - {"description":"A"*1024,"hits":0,"images":["","","","",""],"likes":1234,"nsfw":False,"pfp":"","qrt":{},"rts":1234,"screen_name":"TEST","thumbnail":"","time":"","tweet":"https://twitter.com/TEST/status/1234","type":"Text","uploader":"Test","url":""} - }) - resp = client.get('https://twitter.com/TEST/status/1234'.replace("https://twitter.com",""),headers={"User-Agent":"test"}) - assert resp.status_code==200 - - -def test_directEmbed(): - resp = client.get(testVideoTweet.replace("https://twitter.com","")+".mp4",headers={"User-Agent":"test"}) - assert resp.status_code==200 - assert testVideoTweet_compare["mediaURLs"][0] in str(resp.data) - -def test_message404(): - resp = client.get("https://twitter.com/jack/status/12345",headers={"User-Agent":"test"}) - assert resp.status_code==200 - assert "Failed to scan your link!" in str(resp.data) - -def test_combine(): - twt = twitfix.getTweetData(testMultiMediaTweet) - img1 = twt["mediaURLs"][0] - img2 = twt["mediaURLs"][1] - resp = client.get(f"/rendercombined.jpg?imgs={img1},{img2}",headers={"User-Agent":"test"}) - assert resp.status_code==200 - assert resp.headers["Content-Type"]=="image/jpeg" - assert len(resp.data)>1000 - -def test_calcSyndicationToken(): - assert twExtract.calcSyndicationToken("1691389765483200513") == "43lnobuxzql" \ No newline at end of file diff --git a/test_vx_VNF.py b/test_vx_VNF.py new file mode 100644 index 0000000..ec1ef67 --- /dev/null +++ b/test_vx_VNF.py @@ -0,0 +1,27 @@ +import twitfix +from vx_testdata import * + +def getVNFFromLink(link): + return twitfix.getTweetData(link) + +## VNF conversion test ## +def test_textTweetVNF(): + vnf = getVNFFromLink(testTextTweet) + compareDict(testTextTweet_compare,vnf) + +def test_videoTweetVNF(): + vnf = getVNFFromLink(testVideoTweet) + + compareDict(testVideoTweet_compare,vnf) + +def test_mediaTweetVNF(): + vnf = getVNFFromLink(testMediaTweet) + compareDict(testMediaTweet_compare,vnf) + +def test_multimediaTweetVNF(): + vnf = getVNFFromLink(testMultiMediaTweet) + compareDict(testMultiMediaTweet_compare,vnf) + +def test_pollTweetVNF(): + vnf = getVNFFromLink(testPollTweet) + compareDict(testPollTweet_compare,vnf) \ No newline at end of file diff --git a/test_vx_embeds.py b/test_vx_embeds.py new file mode 100644 index 0000000..06f2f9b --- /dev/null +++ b/test_vx_embeds.py @@ -0,0 +1,82 @@ +import os + +import twitfix,twExtract +import cache +from flask.testing import FlaskClient +from vx_testdata import * +client = FlaskClient(twitfix.app) + +def test_embed_qrtTweet(): + cache.clearCache() + # this is an incredibly lazy test, todo: improve it in the future + resp = client.get(testQRTTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"}) + assert resp.status_code==200 + assert testQRTTweet_compare['text'][:10] in str(resp.data) + # test qrt-ception + resp = client.get(testQrtCeptionTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"}) # get top level tweet + assert resp.status_code==200 + assert "Please retweet this to spread awareness for retweets" in str(resp.data) + qtd_tweet=cache.getVnfFromLinkCache("https://twitter.com/EliLanger/status/585253161260216320") # check that the quoted tweet for the top level tweet is cached + assert qtd_tweet is not None + assert qtd_tweet["qrtURL"] is not None # check that the quoted tweet for the top level tweet has a qrtURL + assert cache.getVnfFromLinkCache("https://twitter.com/EliLanger/status/313143446842007553") is None # check that the bottom level tweet has NOT been cached + resp = client.get("/EliLanger/status/585253161260216320",headers={"User-Agent":"test"}) # get mid level tweet + assert resp.status_code==200 + assert cache.getVnfFromLinkCache("https://twitter.com/EliLanger/status/313143446842007553") is not None # check that the bottom level tweet has been cached now + +def test_embed_qrtVideoTweet(): + cache.clearCache() + # this is an incredibly lazy test, todo: improve it in the future + resp = client.get(testQrtVideoTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"}) + assert resp.status_code==200 + qtd_tweet=cache.getVnfFromLinkCache("https://twitter.com/i/status/1674197531301904388") + vurl = qtd_tweet["mediaURLs"][0] + assert f"twitter:player:stream\" content=\"{vurl}" in str(resp.data) + +def test_embed_FromScratch(): + cache.clearCache() + client.get(testTextTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"}) + client.get(testVideoTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"}) + client.get(testMediaTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"}) + client.get(testMultiMediaTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"}) + +def test_embed_FromCache(): + cache.clearCache() + twitfix.getTweetData(testTextTweet) + twitfix.getTweetData(testVideoTweet) + twitfix.getTweetData(testMediaTweet) + twitfix.getTweetData(testMultiMediaTweet) + #embed time + resp = client.get(testTextTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"}) + assert resp.status_code==200 + resp = client.get(testVideoTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"}) + assert resp.status_code==200 + resp = client.get(testMediaTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"}) + assert resp.status_code==200 + resp = client.get(testMultiMediaTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"}) + assert resp.status_code==200 + +def test_embed_Suggestive(): + resp = client.get(testNSFWTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"}) + assert resp.status_code==200 + assert "so i had a bot generate it for me" in str(resp.data) + assert "FfF_gKwXgAIpnpD" in str(resp.data) + +def test_embed_direct(): + resp = client.get(testVideoTweet.replace("https://twitter.com","")+".mp4",headers={"User-Agent":"test"}) + assert resp.status_code==200 + assert testVideoTweet_compare["mediaURLs"][0] in str(resp.data) + +def test_embed_message404(): + resp = client.get("https://twitter.com/jack/status/12345",headers={"User-Agent":"test"}) + assert resp.status_code==200 + assert "Failed to scan your link!" in str(resp.data) + +def test_combine(): + twt = twitfix.getTweetData(testMultiMediaTweet) + img1 = twt["mediaURLs"][0] + img2 = twt["mediaURLs"][1] + resp = client.get(f"/rendercombined.jpg?imgs={img1},{img2}",headers={"User-Agent":"test"}) + assert resp.status_code==200 + assert resp.headers["Content-Type"]=="image/jpeg" + assert len(resp.data)>1000 \ No newline at end of file diff --git a/test_vx_extract.py b/test_vx_extract.py new file mode 100644 index 0000000..2114531 --- /dev/null +++ b/test_vx_extract.py @@ -0,0 +1,93 @@ +import os + +import twExtract +from vx_testdata import * + +def test_twextract_syndicationAPI(): + tweet = twExtract.extractStatus_syndication(testMediaTweet,workaroundTokens=tokens) + assert tweet["full_text"]==testMediaTweet_compare['text'] + +def test_twextract_extractStatusV2Anon(): + tweet = twExtract.extractStatusV2AnonLegacy(testTextTweet,None) + assert tweet["full_text"]==testTextTweet_compare['text'] + tweet = twExtract.extractStatusV2AnonLegacy(testVideoTweet,None) + assert tweet["full_text"]==testVideoTweet_compare['text'] + tweet = twExtract.extractStatusV2AnonLegacy(testMediaTweet,None) + assert tweet["full_text"]==testMediaTweet_compare['text'] + tweet = twExtract.extractStatusV2AnonLegacy(testMultiMediaTweet,None) + assert tweet["full_text"][:94]==testMultiMediaTweet_compare['text'][:94] + + +def test_twextract_v2API(): + tweet = twExtract.extractStatusV2Legacy(testMediaTweet,workaroundTokens=tokens) + assert tweet["full_text"]==testMediaTweet_compare['text'] + +## Tweet retrieve tests ## +def test_twextract_textTweetExtract(): + tweet = twExtract.extractStatus(testTextTweet,workaroundTokens=tokens) + assert tweet["full_text"]==testTextTweet_compare['text'] + assert tweet["user"]["screen_name"]=="jack" + assert 'extended_entities' not in tweet + +def test_twextract_extractV2(): # remove this when v2 is default + tweet = twExtract.extractStatusV2(testTextTweet,workaroundTokens=tokens) + +def test_twextract_UserExtract(): + user = twExtract.extractUser(testUser,workaroundTokens=tokens) + assert user["screen_name"]=="jack" + assert user["id"]==12 + assert user["created_at"] == "Tue Mar 21 20:50:14 +0000 2006" + +def test_twextract_UserExtractID(): + user = twExtract.extractUser(testUserID,workaroundTokens=tokens) + assert user["screen_name"]=="jack" + assert user["id"]==12 + assert user["created_at"] == "Tue Mar 21 20:50:14 +0000 2006" + +def test_twextract_UserExtractWeirdURLs(): + for url in testUserWeirdURLs: + user = twExtract.extractUser(url,workaroundTokens=tokens) + assert user["screen_name"]=="jack" + assert user["id"]==12 + assert user["created_at"] == "Tue Mar 21 20:50:14 +0000 2006" + +def test_twextract_videoTweetExtract(): + tweet = twExtract.extractStatus(testVideoTweet,workaroundTokens=tokens) + assert tweet["full_text"]==testVideoTweet_compare['text'] + assert 'extended_entities' in tweet + assert len(tweet['extended_entities']["media"])==1 + video = tweet['extended_entities']["media"][0] + assert video["media_url_https"]==testVideoTweet_compare['media_extended'][0]['thumbnail_url'] + assert video["type"]=="video" + + +def test_twextract_mediaTweetExtract(): + tweet = twExtract.extractStatus(testMediaTweet,workaroundTokens=tokens) + assert tweet["full_text"]==testMediaTweet_compare['text'] + assert 'extended_entities' in tweet + assert len(tweet['extended_entities']["media"])==1 + video = tweet['extended_entities']["media"][0] + + assert video["media_url_https"]==testMediaTweet_compare['media_extended'][0]['thumbnail_url'] + assert video["type"]=="photo" + + +def test_twextract_multimediaTweetExtract(): + tweet = twExtract.extractStatus(testMultiMediaTweet,workaroundTokens=tokens) + assert tweet["full_text"][:94]==testMultiMediaTweet_compare['text'][:94] + assert 'extended_entities' in tweet + assert len(tweet['extended_entities']["media"])==3 + video = tweet['extended_entities']["media"][0] + assert video["media_url_https"]==testMultiMediaTweet_compare["mediaURLs"][0] + assert video["type"]=="photo" + video = tweet['extended_entities']["media"][1] + assert video["media_url_https"]==testMultiMediaTweet_compare["mediaURLs"][1] + assert video["type"]=="photo" + +def test_twextract_pollTweetExtract(): # basic check if poll data exists + tweet = twExtract.extractStatus("https://twitter.com/norm/status/651169346518056960",workaroundTokens=tokens) + assert 'card' in tweet + assert tweet['card']['name']=="poll2choice_text_only" + +def test_twextract_NSFW_TweetExtract(): + tweet = twExtract.extractStatus(testNSFWTweet,workaroundTokens=tokens) # For now just test that there's no error \ No newline at end of file diff --git a/test_vx_misc.py b/test_vx_misc.py new file mode 100644 index 0000000..4cd2455 --- /dev/null +++ b/test_vx_misc.py @@ -0,0 +1,18 @@ +import twitfix, cache, twExtract +from vx_testdata import * + +def test_calcSyndicationToken(): + assert twExtract.calcSyndicationToken("1691389765483200513") == "43lnobuxzql" + +def test_addToCache(): + cache.clearCache() + twitfix.getTweetData(testTextTweet) + twitfix.getTweetData(testVideoTweet) + twitfix.getTweetData(testMediaTweet) + twitfix.getTweetData(testMultiMediaTweet) + #retrieve + compareDict(testTextTweet_compare,cache.getVnfFromLinkCache(testTextTweet)) + compareDict(testVideoTweet_compare,cache.getVnfFromLinkCache(testVideoTweet)) + compareDict(testMediaTweet_compare,cache.getVnfFromLinkCache(testMediaTweet)) + compareDict(testMultiMediaTweet_compare,cache.getVnfFromLinkCache(testMultiMediaTweet)) + cache.clearCache() \ No newline at end of file diff --git a/vx_testdata.py b/vx_testdata.py new file mode 100644 index 0000000..eccc5ba --- /dev/null +++ b/vx_testdata.py @@ -0,0 +1,39 @@ +import os + +# autogenerated from testgen.py +testTextTweet="https://twitter.com/jack/status/20" +testVideoTweet="https://twitter.com/pdxdylan/status/1540398733669666818" +testMediaTweet="https://twitter.com/pdxdylan/status/1534672932106035200" +testMultiMediaTweet="https://twitter.com/pdxdylan/status/1532006436703715331" +testQRTTweet="https://twitter.com/pdxdylan/status/1611477137319514129" +testQrtCeptionTweet="https://twitter.com/CatherineShu/status/585253766271672320" +testQrtVideoTweet="https://twitter.com/pdxdylan/status/1674561759422578690" +testNSFWTweet="https://twitter.com/kuyacoy/status/1581185279376838657" +testPollTweet="https://twitter.com/norm/status/651169346518056960" + +testTextTweet_compare={'text': 'just setting up my twttr', 'date': 'Tue Mar 21 20:50:14 +0000 2006', 'tweetURL': 'https://twitter.com/jack/status/20', 'tweetID': '20', 'conversationID': '20', 'mediaURLs': [], 'media_extended': [], 'possibly_sensitive': False, 'hashtags': [], 'qrtURL': None, 'allSameType': False, 'hasMedia': False, 'combinedMediaUrl': None, 'pollData': None, 'date_epoch': 1142974214} +testVideoTweet_compare={'text': 'TikTok embeds on Discord/Telegram bait you with a fake play button, but to see the actual video you have to go to their website.\nAs a request from a friend, I made it so that if you add "vx" before "tiktok" on any link, it fixes that. https://t.co/QYpiVXUIrW', 'date': 'Fri Jun 24 18:17:31 +0000 2022', 'tweetURL': 'https://twitter.com/pdxdylan/status/1540398733669666818', 'tweetID': '1540398733669666818', 'conversationID': '1540398733669666818', 'mediaURLs': ['https://video.twimg.com/ext_tw_video/1540396699037929472/pu/vid/762x528/YxbXbT3X7vq4LWfC.mp4?tag=12'], 'media_extended': [{'url': 'https://video.twimg.com/ext_tw_video/1540396699037929472/pu/vid/762x528/YxbXbT3X7vq4LWfC.mp4?tag=12', 'type': 'video', 'size': {'width': 762, 'height': 528}, 'duration_millis': 13650, 'thumbnail_url': 'https://pbs.twimg.com/ext_tw_video_thumb/1540396699037929472/pu/img/l187Z6B9AHHxUKPV.jpg', 'altText': None}], 'possibly_sensitive': False, 'hashtags': [], 'qrtURL': None, 'allSameType': False, 'hasMedia': True, 'combinedMediaUrl': None, 'pollData': None, 'date_epoch': 1656094651} +testMediaTweet_compare={'text': 'oh. https://t.co/HgLAbiXw2E', 'date': 'Wed Jun 08 23:05:14 +0000 2022', 'tweetURL': 'https://twitter.com/pdxdylan/status/1534672932106035200', 'tweetID': '1534672932106035200', 'conversationID': '1534672673422381057', 'mediaURLs': ['https://pbs.twimg.com/media/FUxAt5LWUAMol0N.png'], 'media_extended': [{'url': 'https://pbs.twimg.com/media/FUxAt5LWUAMol0N.png', 'altText': None, 'type': 'image', 'size': {'width': 927, 'height': 534}, 'thumbnail_url': 'https://pbs.twimg.com/media/FUxAt5LWUAMol0N.png'}], 'possibly_sensitive': False, 'hashtags': [], 'qrtURL': None, 'allSameType': False, 'hasMedia': True, 'combinedMediaUrl': None, 'pollData': None, 'date_epoch': 1654729514} +testMultiMediaTweet_compare={'text': 'Released #Retro64 1.0.9. Besides a lot of internal bug-fixes, this adds quicksand blocks, fixes the rendering for the castle stairs block, and adds a new model, Sonic! \nhttps://github.com/Retro64Mod/Retro64Mod/releases/tag/1.18.2-1.0.9 https://t.co/CWZaw4hzyg', 'date': 'Wed Jun 01 14:29:32 +0000 2022', 'tweetURL': 'https://twitter.com/pdxdylan/status/1532006436703715331', 'tweetID': '1532006436703715331', 'conversationID': '1532006436703715331', 'mediaURLs': ['https://pbs.twimg.com/media/FULF9oxXwAMDI-C.png', 'https://pbs.twimg.com/media/FULGaHkWYAIBV5U.png', 'https://pbs.twimg.com/media/FULGiZnWQAMBRWl.png'], 'media_extended': [{'url': 'https://pbs.twimg.com/media/FULF9oxXwAMDI-C.png', 'altText': None, 'type': 'image', 'size': {'width': 507, 'height': 507}, 'thumbnail_url': 'https://pbs.twimg.com/media/FULF9oxXwAMDI-C.png'}, {'url': 'https://pbs.twimg.com/media/FULGaHkWYAIBV5U.png', 'altText': None, 'type': 'image', 'size': {'width': 396, 'height': 431}, 'thumbnail_url': 'https://pbs.twimg.com/media/FULGaHkWYAIBV5U.png'}, {'url': 'https://pbs.twimg.com/media/FULGiZnWQAMBRWl.png', 'altText': None, 'type': 'image', 'size': {'width': 399, 'height': 341}, 'thumbnail_url': 'https://pbs.twimg.com/media/FULGiZnWQAMBRWl.png'}], 'possibly_sensitive': False, 'hashtags': ['Retro64'], 'qrtURL': None, 'allSameType': True, 'hasMedia': True, 'combinedMediaUrl': 'https://vxtwitter.com/rendercombined.jpg?imgs=https://pbs.twimg.com/media/FULF9oxXwAMDI-C.png,https://pbs.twimg.com/media/FULGaHkWYAIBV5U.png,https://pbs.twimg.com/media/FULGiZnWQAMBRWl.png', 'pollData': None, 'date_epoch': 1654093772} +testQRTTweet_compare={'text': "vxTwitter has gotten a *ton* of usage recently, so I'd appreciate a donation to keep things running!\n", 'date': 'Fri Jan 06 21:37:43 +0000 2023', 'tweetURL': 'https://twitter.com/pdxdylan/status/1611477137319514129', 'tweetID': '1611477137319514129', 'conversationID': '1611476665821003776', 'mediaURLs': [], 'media_extended': [], 'possibly_sensitive': False, 'hashtags': [], 'qrtURL': 'https://twitter.com/i/status/1518309187515781125', 'allSameType': False, 'hasMedia': False, 'combinedMediaUrl': None, 'pollData': None, 'date_epoch': 1673041063} +testQrtCeptionTweet_compare={'text': 'Testing retweetception ', 'date': 'Tue Apr 07 01:32:26 +0000 2015', 'tweetURL': 'https://twitter.com/CatherineShu/status/585253766271672320', 'tweetID': '585253766271672320', 'conversationID': '585253766271672320', 'mediaURLs': [], 'media_extended': [], 'possibly_sensitive': False, 'hashtags': [], 'qrtURL': 'https://twitter.com/i/status/585253161260216320', 'allSameType': False, 'hasMedia': False, 'combinedMediaUrl': None, 'pollData': None, 'date_epoch': 1428370346} +testQrtVideoTweet_compare={'text': 'good', 'date': 'Thu Jun 29 23:33:29 +0000 2023', 'tweetURL': 'https://twitter.com/pdxdylan/status/1674561759422578690', 'tweetID': '1674561759422578690', 'conversationID': '1674561759422578690', 'mediaURLs': [], 'media_extended': [], 'possibly_sensitive': False, 'hashtags': [], 'qrtURL': 'https://twitter.com/i/status/1674197531301904388', 'allSameType': False, 'hasMedia': False, 'combinedMediaUrl': None, 'pollData': None, 'date_epoch': 1688081609} +testNSFWTweet_compare={'text': "ngl, I'm scared on finding out the cute Sprigatito's final evolution..\n\nso i had a bot generate it for me.... and I'm forever scarred https://t.co/itMay87vcS", 'date': 'Sat Oct 15 07:28:42 +0000 2022', 'tweetURL': 'https://twitter.com/kuyacoy/status/1581185279376838657', 'tweetID': '1581185279376838657', 'conversationID': '1581185279376838657', 'mediaURLs': ['https://pbs.twimg.com/media/FfF_gKwXgAIpnpD.jpg'], 'media_extended': [{'url': 'https://pbs.twimg.com/media/FfF_gKwXgAIpnpD.jpg', 'altText': None, 'type': 'image', 'size': {'width': 760, 'height': 926}, 'thumbnail_url': 'https://pbs.twimg.com/media/FfF_gKwXgAIpnpD.jpg'}], 'possibly_sensitive': False, 'hashtags': [], 'qrtURL': None, 'allSameType': False, 'hasMedia': True, 'combinedMediaUrl': None, 'pollData': None, 'date_epoch': 1665818922} +testPollTweet_compare={'text': 'I know when that hotline bling, that can only:', 'date': 'Mon Oct 05 22:57:25 +0000 2015', 'tweetURL': 'https://twitter.com/norm/status/651169346518056960', 'tweetID': '651169346518056960', 'conversationID': '651169346518056960', 'mediaURLs': [], 'media_extended': [], 'possibly_sensitive': False, 'hashtags': [], 'qrtURL': None, 'allSameType': False, 'hasMedia': False, 'combinedMediaUrl': None, 'pollData': {'options': [{'name': 'Mean one thing', 'votes': 124875, 'percent': 78.82}, {'name': 'Mean multiple things', 'votes': 33554, 'percent': 21.18}]}, 'date_epoch': 1444085845} + +testUser="https://twitter.com/jack" +testUserID = "https://twitter.com/i/user/12" +testUserWeirdURLs=["https://twitter.com/jack?lang=en","https://twitter.com/jack/with_replies","https://twitter.com/jack/media","https://twitter.com/jack/likes","https://twitter.com/jack/with_replies?lang=en","https://twitter.com/jack/media?lang=en","https://twitter.com/jack/likes?lang=en","https://twitter.com/jack/"] +testTextTweet="https://twitter.com/jack/status/20" + +tokens=os.getenv("VXTWITTER_WORKAROUND_TOKENS",None).split(',') + +def compareDict(original,compare): + for key in original: + assert key in compare + if type(compare[key]) is not dict: + if (key == 'verified' or key== 'time') and compare[key]!=original[key]: + continue # does not match as test data was from before verification changes + assert compare[key]==original[key] + else: + compareDict(original[key],compare[key]) \ No newline at end of file