Buscar/Melhore uma ferramenta de testes de mutação com base no código e nos testes atuais

Melhore uma ferramenta de testes de mutação com base no código e nos testes atuais

Para alterar uma ferramenta de testes de mutação. Confere primeiro o código e os testes atuais, preserva a ordem de processamento e a avaliação tardia, cria mutadores sem mutantes inválidos, escreve testes que os detectam e segue passos seguros de revisão, CI e lançamento.

Para usar estas regras de IA
## Confira o código, os testes e as notas de design atuais antes de cada mudança Trate a árvore de código atual, os testes, os esquemas, as decisões de arquitetura e a documentação para colaboradores como a especificação. Não confie na memória, em suposições antigas nem em um padrão genérico de sistema quando as evidências do repositório discordarem. Para cada funcionalidade ou correção: 1. Pesquise os testes unitários, de integração, de ponta a ponta, de arquitetura e de automutação mais próximos, incluindo nomes relacionados, falhas, entradas inválidas e casos extremos. 2. Leia a implementação responsável para entender a ordem, os valores padrão, a semântica das falhas e as restrições de desempenho. 3. Leia os registros de projeto referenciados e as discussões do projeto de origem quando a intenção não estiver clara no código. 4. Escreva ou adapte um caso específico que falhe antes da implementação e vincule-o às evidências correspondentes. 5. Registre a razão de mecanismos não evidentes, limites de versão e incompatibilidades deliberadas. Use o glossário do projeto de forma consistente. Modele uma mutação como uma descrição serializável que possa ser aplicada em outro processo e modele um mutador como uma verificação distinta de elegibilidade seguida de uma transformação. Mapeie o fluxo de execução antes de alterá-lo: configuração, coleta de código-fonte e cobertura, enriquecimento da AST, geração de mutações, execução de mutantes, análise posterior opcional e geração de relatórios são limites ordenados de responsabilidade. Se uma alteração invalidar um caminho, uma verificação ou uma convenção documentada, atualize essa documentação na mesma alteração. ## Siga as regras da API pública, dos tipos e dos nomes - O código de produção não pode depender de testes nem de medições de desempenho. Coloque os auxiliares de teste distribuídos em um espaço de nomes de teste explicitamente voltado à produção e imponha mecanicamente a direção da dependência. - Trate a API pública como uma lista de permissões. Marque todo o restante como interno, documente os pontos de extensão e classifique qualquer alteração nessa lista como um evento de compatibilidade. - Use `final` de modo rígido apenas em classes que nunca sejam substituídas por objetos simulados. Mantenha os serviços que podem ser simulados tecnicamente sobrescrevíveis, sem adicionar uma interface apenas para simular uma única classe. - Importe funções e constantes de forma consistente. Para chamadas que podem retornar `false`, escolha uma semântica explícita de falha: use um invólucro seguro quando a falha for excepcional e um alias inseguro com nome claro quando o retorno false for necessário. - Prefira constantes tipadas, marcadores explícitos de sobrescrita e objetos de valor imutáveis. Não torne uma classe `readonly` quando ela memoizar resultados em suas próprias propriedades. - Use asserções em tempo de execução apenas para invariantes que a análise estática não possa provar. A mensagem da asserção deve identificar o erro que uma falha indicaria. - Faça os nomes expressarem contratos: `find*` retorna um valor anulável, `get*` garante um valor, construtores nomeados expressam significado de domínio e exceções descrevem a falha de domínio, em vez de terminar genericamente em `Exception`. - Reserve `Memoized*` para reutilização invisível uma vez por instância. Use `Cached*` apenas quando os chamadores puderem observar chaves, invalidação, TTL ou um armazenamento compartilhado. - Torne não instanciáveis as classes puramente estáticas ou compostas apenas de constantes. Reserve a injeção de dependência para colaboradores com estado ou que realizem E/S. - Mantenha identificável o código copiado do projeto de origem, preserve sua atribuição e documente cada desvio local intencional. ## Preserve a avaliação tardia e passe comandos de subprocessos como arrays de argumentos - Represente valores reutilizáveis e dispendiosos com uma abstração diferida com memoização. Um gerador puro admite apenas uma passagem e não pode ser retrocedido, contado nem armazenado em memória intermediária. - Diferencie um mapeamento estrito de um para um de um mapeamento expansivo de um para muitos. Não deixe nomes de métodos semelhantes ocultarem cardinalidades diferentes do fluxo. - Permita mutação por referência em um trecho crítico medido apenas quando sua propriedade e seu efeito no próprio local estiverem documentados. - Injete abstrações de relógio e sistema de arquivos, em vez de chamar diretamente primitivas de tempo ou disco. Os testes devem controlar os resultados de tempo e do sistema de arquivos. - Represente comandos de subprocessos como listas de argumentos de texto do início ao fim. Cada elemento da lista corresponde exatamente a um argumento; nunca una previamente um comando do interpretador nem suponha divisão por espaços em branco. - Mantenha um único registro explícito de serviços, com métodos de acesso tipados e fábricas inicializadas sob demanda. Os consumidores não podem usar uma busca de serviço sem tipo, e serviços especulativos inalcançáveis são proibidos. - Refaça a vinculação da configuração clonando o contêiner, em vez de alterar o estado compartilhado do processo. Extraia um construtor tipado quando uma função de ligação se tornar complexa. - Combine a configuração conforme a semântica de cada campo: sobrescritas anuláveis usam coalescência de nulo, enquanto indicadores que qualquer uma das fontes pode ativar usam OU lógico. Unificar essas regras altera silenciosamente o comportamento. - Resolva caminhos de saída relativos com base no local do arquivo de configuração, preserve caminhos de fluxo explicitamente permitidos e calcule uma base de controle de versão para processar apenas as alterações pretendidas pelo usuário. ## Mantenha a ordem de processamento da AST sem alterar a árvore original - Trate a ordem de registro dos visitantes como parte do algoritmo. Resolva nomes e pais antes dos consumidores, aplique exclusões antes de anexar testes e redefina o estado reutilizável dos visitantes antes de cada arquivo. - Comunique informações por meio de métodos de acesso tipados aos atributos dos nós. Uma exclusão marca um nó como inelegível; ela nunca remove nem substitui nós durante o enriquecimento. - Anexe consultas dispendiosas de cobertura de forma tardia e apenas aos nós elegíveis. Preserve os dois níveis de avaliação tardia entre a descoberta de arquivos de cobertura e a leitura, por arquivo, dos locais de teste. - Encaminhe consultas XML por um invólucro seguro e ciente de espaços de nomes. Preserve as sequências ordenadas de formatos alternativos e a justificativa de suas versões; uma limpeza não pode eliminar uma ramificação ainda compatível. - Mantenha a execução dos processos em fluxo contínuo. Os identificadores de processos de trabalho consumidos pelos testes dos usuários são valores exatos da API, com início em 1. A análise posterior pertence à cadeia de contêineres de processos, não a ramificações específicas do agendador. - Preserve a semântica das unidades nos cálculos de agendamento: o tempo gasto enfileirando trabalho é uma duração, não uma contagem de itens. Libere referências a contêineres concluídos antes de reutilizar posições de processos de trabalho. - Mantenha separadas e combináveis as alterações de configuração específicas de cada versão do executor de testes. Preserve a configuração moderna de cobertura que serve de referência, os filtros de inclusão do usuário, os caminhos compatíveis com padrões glob e os formatos antigos de documento. - Faça a correspondência de um alvo de mutação pelas posições dos tokens e pela classe do nó. Clone a AST original antes da mutação, preserve os tokens originais para uma impressão que mantenha a formatação e deixe a árvore original equivalente byte a byte. - Trate os hashes de mutação, a ordem dos campos e os atributos de posição obrigatórios como contratos públicos de repetição. Copie cada filho e atributo ao reconstruir nós; uma substituição válida pode ser um valor escalar, um nó ou uma lista de nós. ## Crie mutadores que não gerem mutantes inválidos nem equivalentes Uma alteração completa de mutador atualiza a implementação, todos os registros centrais e mapas de perfis, o esquema de configuração, um teste canônico e a documentação do usuário quando o comportamento for público. - Mantenha mínima a superfície pública do mutador: definição, nome estável, elegibilidade e transformação, além de acesso à configuração apenas quando o mutador for configurável. - Faça a definição explicar a mutação, a categoria, um exemplo comparativo da alteração e como o usuário pode eliminar o mutante. - Nas verificações de elegibilidade, compare identificadores da linguagem segundo suas regras reais de maiúsculas e minúsculas e percorra os nós ancestrais quando o contexto aninhado for relevante. - Nunca gere erros de sintaxe, erros fatais garantidos, mutações equivalentes, ciclos infinitos nem uma mutação que já pertença a outro mutador. - Quando houver possibilidade de sobreposição ou equivalência, registre a justificativa e adicione um caso nomeado sem mutação. - Copie todos os filhos e metadados ao construir um nó substituto da AST, para que atributos não sejam eliminados silenciosamente. - Exercite os mutadores pela infraestrutura de travessia usada em produção. Não crie um percurso isolado que ignore o comportamento de elegibilidade ou de escopo. - Trate a ausência de uma saída esperada como uma asserção explícita de que não há mutação e faça os nomes dos conjuntos de dados funcionarem como especificações. - Relate, por mutador, as quantidades de mutantes gerados, eliminados, sobreviventes e encerrados por tempo excedido quando o volume de mutações mudar. ## Escreva testes repetíveis que detectem os mutantes - Dê a cada classe-fonte concreta um teste canônico e a cada teste um alvo explícito de cobertura. - Classifique testes com E/S como testes de integração e testes sem E/S como testes que não são de integração. Imponha esse limite nos dois sentidos. - Mantenha os testes determinísticos: use caminhos temporários gerados, fixe a concorrência em dados de teste sensíveis à ordem da saída, faça cópias de segurança das variáveis de ambiente e evite caminhos inexistentes escritos diretamente. - Use provedores de dados estáticos com nomes de casos descritivos. Prefira argumentos nomeados e valores padrão em assinaturas de teste extensas, mas não compartilhe um provedor entre testes que consumam subconjuntos diferentes. - Substitua redes profundas de objetos simulados por pequenos construtores imutáveis ou implementações falsas. Faça as expectativas sobre objetos simulados verificarem argumentos exatos, para que mutações não escapem por asserções permissivas. - Estruture o código de produção para tornar as mutações visíveis: prefira retornos antecipados, resultados booleanos separados e constantes nomeadas a literais mágicos impossíveis de testar. - Evite argumentos padrão em construtores que ocultem dependências ausentes. Valores padrão em provedores de dados são aceitáveis quando fazem cada caso declarar apenas o que varia. - Use as infraestruturas de teste de visitantes, comandos e demais preparações alinhadas à produção oferecidas pelo projeto. Não escreva um script descartável de sondagem quando deveria existir um teste unitário específico. - Um mutante sobrevivente indica um teste ausente ou um código que precisa ser reformulado. Discuta casos realmente impossíveis de eliminar ou voltados apenas ao desempenho, em vez de escrever um teste artificial. - Durante a iteração, execute testes específicos. Antes da entrega, execute o formatador do repositório, a revisão de arquitetura e análise estática, os grupos de integração pertinentes e o conjunto completo de testes que serve de referência. ## Mantenha configurações por versão e alternativas ao limpar o código - Mantenha os limites de versão e as sequências escalonadas de alternativas documentados junto ao comportamento que protegem. Não simplifique uma matriz de compatibilidade apenas porque somente o formato mais recente é familiar. - Em minilinguagens de configuração ordenadas, processe as chaves em sequência e deixe prevalecer as entradas posteriores. Um sentinela `false` deve remover tudo o que foi registrado por essa chave, inclusive perfis aninhados. - Preserve a direção da combinação e a eliminação explícita de duplicatas ao reunir configurações. Uma seleção pela linha de comando pode substituir a seleção por arquivo, mas ainda deve manter as regras globais de exclusão. - Faça de um único registro a fonte de referência para todo o universo de mutadores compatíveis e derive dele verificações automatizadas de cobertura. - Quando um filtro de nomes de testes se aproximar do limite das expressões regulares, passe da filtragem precisa para um superconjunto seguro e, por fim, omita o filtro para que todo o conjunto de testes seja executado. Nunca regrida para uma execução sem teste algum. - Preserve a regra associada segundo a qual o resultado “nenhum teste executado” de um executor é aprovado quando uma seleção vazia é válida. - Após uma reinicialização sem depurador, não deduza a capacidade pela extensão carregada no momento. Consulte o controlador da reinicialização para saber qual versão foi ignorada e habilite a cobertura apenas no processo filho que precisar dela. - Aplique ajustes do limite de memória apenas à configuração temporária do processo filho, depois da análise estática, e faça o ajuste em regime de melhor esforço com proteções explícitas. - Meça otimizações que usam muitos processos antes de mantê-las. Reavalie soluções alternativas antigas de desempenho quando mudarem as versões do ambiente de execução ou da cadeia de ferramentas. ## Proteja o lockfile e faça merge apenas de pull requests com a CI aprovada Nunca ignore um arquivo de bloqueio congelado durante uma instalação não supervisionada. Se a resolução de dependências exigir uma alteração nesse arquivo, pare e obtenha autorização explícita. Versões exatas, hashes de integridade e compatibilidade de licenças são limites da cadeia de suprimentos. Nunca envie alterações diretamente ao ramo padrão protegido, contorne sua proteção nem force uma integração administrativa. Use esta sequência: 1. Crie um ramo de funcionalidade específico. 2. Faça a menor alteração coerente e execute verificações direcionadas. 3. Registre a alteração com a convenção de mensagens exigida pelo repositório. 4. Envie o ramo e abra uma solicitação de integração. 5. Aguarde todas as verificações obrigatórias de formatação, tipos, testes unitários, de integração e de ponta a ponta. 6. Corrija as falhas em vez de contorná-las. 7. Integre pelo método aprovado e remova o ramo. Não misture refatoração com alterações de comportamento. Erros corrigidos exigem testes de regressão, quebras de compatibilidade exigem notas explícitas de lançamento e orientações de migração, e comportamentos visíveis ao usuário exigem documentação do usuário sincronizada. Deixe a automação de lançamento derivar metadados de mensagens de registro convencionais. Use substituições documentadas apenas para reclassificações deliberadas e nunca edite manualmente artefatos de lançamento gerados. Execute a integração contínua para contribuições não confiáveis sem segredos e com permissões somente de leitura. Pré-visualizações que usem segredos devem ignorar bifurcações, salvo quando um responsável autorizado as acionar explicitamente por um comando com verificação de identidade. Registre cada exemplo implantado na matriz de compilação e adicione um teste básico de funcionamento para seu caminho, estado e conteúdo. Um lançamento ou uma implantação só estará concluído depois que as verificações obrigatórias e as evidências posteriores à implantação forem aprovadas.