mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2025-07-27 07:38:30 +00:00
doc: teste(twitter): adicionar testes unitários para a lógica de disponibilidade do Twitter Space
This commit is contained in:
parent
2b6fbda4d4
commit
7b34f22826
1
test/test_AeonCo_2_emyi4z-O0ls.info.json
Normal file
1
test/test_AeonCo_2_emyi4z-O0ls.info.json
Normal file
File diff suppressed because one or more lines are too long
22
test/test_donate.py
Normal file
22
test/test_donate.py
Normal file
@ -0,0 +1,22 @@
|
||||
import re
|
||||
import requests
|
||||
|
||||
def read_readme():
|
||||
with open("README.md", "r", encoding="utf-8") as f:
|
||||
return f.read()
|
||||
|
||||
def extract_donate_url(content):
|
||||
match = re.search(r'\[!\[Donate\]\(.*?\)\]\((.*?)\)', content)
|
||||
assert match is not None, "Link de doação não encontrado no README"
|
||||
return match.group(1)
|
||||
|
||||
def test_donate_link_is_absolute():
|
||||
content = read_readme()
|
||||
url = extract_donate_url(content)
|
||||
assert url.startswith("https://"), f"URL não é absoluta: {url}"
|
||||
|
||||
def test_donate_link_is_accessible():
|
||||
content = read_readme()
|
||||
url = extract_donate_url(content)
|
||||
response = requests.get(url)
|
||||
assert response.status_code == 200, f"Link inacessível: status {response.status_code} - {url}"
|
54
test/test_gerador_senha.py
Normal file
54
test/test_gerador_senha.py
Normal file
@ -0,0 +1,54 @@
|
||||
# tests/test_gerador_senha.py
|
||||
import pytest
|
||||
import re
|
||||
from gerador_senha import gerar_senha
|
||||
|
||||
# Ciclo 1 do projeto original: Garante que o erro é lançado se nenhuma opção for selecionada.
|
||||
def test_ciclo1_excecao_sem_criterios():
|
||||
with pytest.raises(ValueError):
|
||||
gerar_senha(5, minusculas=False, maiusculas=False, digitos=False, simbolos=False)
|
||||
|
||||
# Ciclo 2: Nosso alvo para o RED/GREEN de agora.
|
||||
def test_ciclo2_minusculas_apenas():
|
||||
senha = gerar_senha(5, minusculas=True, maiusculas=False, digitos=False, simbolos=False)
|
||||
assert len(senha) == 5
|
||||
assert re.fullmatch(r'[a-z]{5}', senha)
|
||||
|
||||
# Ciclo 3: Teste para minúsculas e maiúsculas.
|
||||
def test_ciclo3_uma_maiuscula():
|
||||
senha = gerar_senha(10, minusculas=True, maiusculas=True, digitos=False, simbolos=False)
|
||||
assert len(senha) == 10
|
||||
assert any(c.isupper() for c in senha)
|
||||
assert any(c.islower() for c in senha)
|
||||
assert all(c.isalpha() for c in senha)
|
||||
|
||||
# Ciclo 4: Teste para minúsculas e dígitos.
|
||||
def test_ciclo4_um_digito():
|
||||
senha = gerar_senha(12, minusculas=True, maiusculas=False, digitos=True, simbolos=False)
|
||||
assert len(senha) == 12
|
||||
assert any(c.isdigit() for c in senha)
|
||||
assert all(c.islower() or c.isdigit() for c in senha)
|
||||
|
||||
# Ciclo 5: Teste para apenas símbolos.
|
||||
def test_ciclo5_um_simbolo():
|
||||
senha = gerar_senha(6, minusculas=False, maiusculas=False, digitos=False, simbolos=True)
|
||||
assert len(senha) == 6
|
||||
assert any(c in "!@#$%&*" for c in senha)
|
||||
assert all(c in "!@#$%&*" for c in senha)
|
||||
|
||||
# Ciclo 6: Teste para todas as categorias.
|
||||
def test_ciclo6_uma_de_cada_categoria():
|
||||
senha = gerar_senha(16, minusculas=True, maiusculas=True, digitos=True, simbolos=True)
|
||||
assert len(senha) == 16
|
||||
assert any(c.islower() for c in senha)
|
||||
assert any(c.isupper() for c in senha)
|
||||
assert any(c.isdigit() for c in senha)
|
||||
assert any(c in "!@#$%&*" for c in senha)
|
||||
|
||||
# Ciclo 7: Teste para minúsculas e símbolos.
|
||||
def test_ciclo7_minusculas_simbolos():
|
||||
senha = gerar_senha(10, minusculas=True, maiusculas=False, digitos=False, simbolos=True)
|
||||
assert len(senha) == 10
|
||||
assert any(c.islower() for c in senha)
|
||||
assert any(c in "!@#$%&*" for c in senha)
|
||||
assert all(c.islower() or c in "!@#$%&*" for c in senha)
|
39
test/test_twitter_spaces_availability.py
Normal file
39
test/test_twitter_spaces_availability.py
Normal file
@ -0,0 +1,39 @@
|
||||
import pytest
|
||||
|
||||
def is_twitter_space_available(metadata):
|
||||
"""
|
||||
Verifica se um Twitter Space está disponível para download.
|
||||
Um espaço só é considerado disponível se:
|
||||
- Não está ao vivo
|
||||
- Não está agendado (upcoming)
|
||||
- Não é privado
|
||||
"""
|
||||
return (
|
||||
metadata.get("is_live") is False
|
||||
and metadata.get("live_status") not in ["is_upcoming", "upcoming"]
|
||||
and metadata.get("availability") != "private"
|
||||
)
|
||||
|
||||
def test_space_is_available_when_not_live_not_upcoming_and_not_private():
|
||||
metadata = {
|
||||
'is_live': False,
|
||||
'live_status': None,
|
||||
'availability': 'public'
|
||||
}
|
||||
assert is_twitter_space_available(metadata) is True, "Twitter Space deveria ser considerado disponível"
|
||||
|
||||
def test_space_is_not_available_when_upcoming():
|
||||
metadata = {
|
||||
'is_live': False,
|
||||
'live_status': "is_upcoming",
|
||||
'availability': 'public'
|
||||
}
|
||||
assert is_twitter_space_available(metadata) is False, "Twitter Space agendado não deveria ser considerado disponível"
|
||||
|
||||
def test_space_is_not_available_when_private():
|
||||
metadata = {
|
||||
'is_live': False,
|
||||
'live_status': None,
|
||||
'availability': 'private'
|
||||
}
|
||||
assert is_twitter_space_available(metadata) is False, "Twitter Space privado não deveria ser considerado disponível"
|
153879
unicodedata
Normal file
153879
unicodedata
Normal file
File diff suppressed because it is too large
Load Diff
42
yt_dlp/postprocessor/writedescription.py
Normal file
42
yt_dlp/postprocessor/writedescription.py
Normal file
@ -0,0 +1,42 @@
|
||||
# yt_dlp/postprocessor/writedescription.py
|
||||
|
||||
import os
|
||||
|
||||
from .common import PostProcessor
|
||||
|
||||
class WriteDescriptionPP(PostProcessor):
|
||||
def __init__(self, downloader, **kwargs):
|
||||
# O nome do PP que será usado na linha de comando é 'writedescription'
|
||||
super().__init__(downloader)
|
||||
|
||||
# O método run é o que executa a lógica do nosso PP
|
||||
def run(self, info):
|
||||
"""Escreve a descrição em um arquivo .description"""
|
||||
|
||||
# Pega o nome do arquivo de vídeo que já foi processado
|
||||
filepath = info.get('filepath')
|
||||
if not filepath:
|
||||
self.to_screen('ERROR: Não foi possível encontrar o caminho do arquivo de vídeo.')
|
||||
return [], info
|
||||
|
||||
# Pega a descrição do dicionário de informações
|
||||
description = info.get('description')
|
||||
if not description:
|
||||
self.to_screen('Vídeo não tem descrição, pulando a criação do arquivo.')
|
||||
return [], info
|
||||
|
||||
# Monta o nome do novo arquivo de descrição
|
||||
desc_filename = os.path.splitext(filepath)[0] + '.description'
|
||||
|
||||
self.to_screen(f'Writing description to: {desc_filename}')
|
||||
|
||||
try:
|
||||
# Escreve o arquivo
|
||||
with open(desc_filename, 'w', encoding='utf-8') as f:
|
||||
f.write(description)
|
||||
except (IOError, OSError) as err:
|
||||
self.report_error(f'Cannot write description file: {err}')
|
||||
return [], info
|
||||
|
||||
# Retorna a lista de arquivos e o dicionário, como esperado pelo yt-dlp
|
||||
return [], info
|
Loading…
Reference in New Issue
Block a user