Skip to main content

the avatar of Zoltán Balogh

Redmine RAG system

The Goal

The goal was to extract all issues from a Redmine instance, anonymize the data, and build a local RAG system for semantic search and Q&A.

Just like with the previous experiment with Bugzilla it started with data extraction. I planned to make a simple bulk download via Redmine API. Then came the first problem. Redmine’s API doesn’t return journal entries (comments) when using the project-level endpoint, even with the include=journals parameter. I tried out different ways but nothing worked. The solution was, after all, to change the strategy and fetch each issue individually via /issues/{id}.json. This was much slower but guaranteed complete data including all comments.

a silhouette of a person's head and shoulders, used as a default avatar

Fediverso y redes sociales no propietarias #Vamonosjuntas

Esta vez voy justo, y me sabe mal porque el ponente de la charla «Fediverso y redes sociales no propietarias #Vamonosjuntas» es David Marzal, uno de los miembros más activos de la podcasfera linuxera que con su KDE Express nos informa con una periodicidad envidiable de las últimas novedades del mundos del Software Libre. Así que voy al grano: mañana viernes de 11 a 13 estáis invitados a asistir a su charla que realizará en el Campus dels Tarongers, Biblioteca de Ciencias Sociales. Sigue leyendo para tener más informacion.

Fediverso y redes sociales no propietarias #Vamonosjuntas

Ya comento que no podré asistir pero que si estuviera por València ni me lo pensaría. David Marzal es buen comunicador y asistir a sus charlas siempre es un lujo.

Es por ello que este viernes 5 de diciembre, a las 11 horas tenéis una cita en el Aula de Formación de la Biblioteca de Ciencias Sociales del Campus de Tarongers, Universidad de Valencia si queréis saber la importancia de tener redes libres y descentralizadas, cuyo propósito sea facilitar la comunicación y no intoxicar la opinión pública y ganar dinero con vuestros datos,

Pero mejor que os lo expliquen los organizadores:

Nosotras también estamos hartas de las redes sociales tóxicas, así que nos hemos mudado a un nuevo barrio: el fediverso. Te invitamos a formar parte de esta comunidad, donde apostamos por un internet más humano, libre y colaborativo. Además, asumimos el compromiso de enfrentar los retos que supone nutrir una herramienta colectiva y descentralizada como ésta, prescribiendo su utilización así como sosteniéndola mediante la movilización de recursos desde la corresponsabilidad que iniciativas como ésta requieren.
David Marzal es administrador de sistemas GNU/Linux de profesión, apasionado por el software libre y la sostenibilidad de vocación. Activista en asociaciones como GNU/Linux Valencia, KDE España o Residuo Cero de la Región de Murcia.
​Actividad gratuita con aforo limitado a 20 personas, por riguroso orden de inscripción.
La inscripción se realiza vía correo-e: cde@uv.es 
 
Con la colaboración del Servei de Biblioteques i Documentació de la Universitat de València. 

Información básica:

Fediverso y redes sociales no propietarias #Vamonosjuntas

Fediverso y redes sociales no propietarias #Vamonosjuntas
Profesor: David Marzal
Viernes, 5 de diciembre de 2025 11-13 h. 
Campus dels Tarongers. Biblioteca de Ciencias Sociales. Aula de formación.

Más información: Centre de Documentació Europea de la Universitat de Valencia

La entrada Fediverso y redes sociales no propietarias #Vamonosjuntas se publicó primero en KDE Blog.

a silhouette of a person's head and shoulders, used as a default avatar

LOUVRE el arte de la ciberseguridad en Compilando Podcast

Hoy me complace compartir con vosotros un nuevo episodio de Compilando Podcast, que ha vuelto con fuerza en forma de episodios tipo píldora muy instructivos. En esta ocasión se trata del episodio 64 que lleva por título «LOUVRE el arte de la ciberseguridad» donde Paco nos hace reflexionar sobre uno de las aspectos que día a día se hace más importante, la ciberseguridad, y su relación con el arte.

LOUVRE el arte de la ciberseguridad en Compilando Podcast

LOUVRE el arte de la ciberseguridad

En palabras del gran Paco Estrada, extraídas de la nueva web de Compilando Podcast y que sirven de introducción del episodio 63:

Una de las mayores instituciones culturales del mundo, el Museo del Louvre, fue protagonista de un suceso que ha dado la vuelta al planeta. Pero más allá del titular y de la famosa contraseña, este episodio no busca hablar del robo, sino de lo que nos revela sobre la naturaleza humana, la tecnología y… el arte.

En Compilando Podcast reflexionamos sobre cómo la ciberseguridad, más que una ciencia exacta, es también una forma de arte: una combinación de técnica, sensibilidad y cultura digital.
Porque proteger sistemas no es solo cuestión de software o hardware, sino de conciencia, de educación y de esa mirada que sabe cuidar los detalles invisibles.

Un episodio para pensar en cómo la destreza, la atención y la responsabilidad se entrelazan también en el mundo digital.

Escúchalo y descubre por qué, incluso en la era de la Inteligencia Artificial, pensamos que la ciberseguridad sigue siendo, ante todo, un arte.

Música: https://incompetech.filmmusic.io/ by Kevin McLeod y musopen.org

Licencia : Creative Commons (CC BY-NC-SA)

Más información: Compilando Podcast

¿Qué es Compilando Podcast?

Dentro del mundo de los audios de Software Libre, que los hay muchos y de calidad, destaca uno por la profesionalidad de la voz que lo lleva, el gran Paco Estrada, y por el mimo con el que está hecho. No es por nada que ganó el Open Awards’18 al mejor medio, un reconocimiento al trabajo realizado por la promoción .

A modo de resumen, Compilando Podcast es un proyecto personal de su locutor Paco Estrada que aúna sus pasiones y que además, nos ofrece una voz prodigiosa y una dicción perfecta.

La entrada LOUVRE el arte de la ciberseguridad en Compilando Podcast se publicó primero en KDE Blog.

the avatar of Zoltán Balogh

I want to have a hot shower

It all started last summer

When my family moved to a new place. In our previous home we had a district heating service that included unlimited hot water for a fixed price. That was awesome - not very environmentally friendly and actually not very cheap, but we never ran out of hot water.

The boiler

In our new home we are independent from the city’s hot water services. This is good because we pay exactly for the energy we use. It means that we have a 300-liter hot water heater that we turn on when we want to make as much hot water as we need. In most households such a hot water boiler has a thermostat set to a specific temperature and the heater keeps all 300 liters of water as hot as it is set. I do not like this, because regardless of how great the insulation on the water tank is, it loses temperature over time. I needed a smarter system.

a silhouette of a person's head and shoulders, used as a default avatar

Últimas dos semanas en las aplicaciones de KDE

Es increíble el trabajo de promoción que está realizando Nate en su blog, desde hace más del tiempo que puedo recordar, ha sido replicado en ocasiones por Carl Schwan hablando de aplicaciones. Igual que Nate, se trata de un resumen de las novedades más destacadas, pero no en forma de telegrama, sino de artículo completo. Dado que en la actualidad tenemos herramientas que nos facilitan la traducción y la edición voy a intentar hacer algo que es simple pero requiere constancia: promocionar dichos artículos facilitando la información a la comunidad hispana que no domina el inglés. Al mismo tiempo hará que yo esté al día y que me entere bien de todo. Bienvenidos pues al artículo de la serie de aplicaciones «Últimas dos semanas en las aplicaciones de KDE«. Espero que os guste y que os ponga los dientes largos viendo lo que nos espera.

Últimas dos semanas en las aplicaciones de KDE

Nota: artículo original en Blogs KDE. Traducción realizada utilizando Perplexity. Esta entrada está llena de novedades en las aplicaciones de la Comunidad KDE.

¡Bienvenido a una nueva edición de «This Week in KDE Apps»! Cada semana (o casi) cubrimos todo lo posible de lo que está sucediendo en el mundo de las aplicaciones de KDE.
Todavía estamos realizando nuestras campañas de recaudación de fondos y en las últimas 48 horas, gracias al increíble apoyo de nuestros usuarios, hemos recaudado más de €90.000. ¡Sigue así y si puedes permitírtelo, dona en kde.org/donate! Cualquier cantidad ayuda.
Volviendo a todo lo nuevo en el panorama de las aplicaciones de KDE, ¡vamos a ello!

Últimas dos semanas en las aplicaciones de KDE

Aplicaciones de viajes

Volker Krause publicó una entrada en su blog sobre el progreso actual de KDE Itinerary en octubre y noviembre. Esto incluye una página de búsqueda de viajes mejorada, control detallado para eliminar billetes, información de altitud en la vista de estado en vivo, ¡y más! Puedes leer todo eso en su blog.

Aplicaciones de multimedia/gráficos

Okular Ver y anotar documentos

  • Mohammad Kazemi añadió una acción de «Copiar sin saltos de línea» para eliminar los saltos de línea al copiar texto (26.04.0 – enlace).
  • Quinten Kock añadió gestos nativos de pellizco con touchpad en Okular (26.04.0 – enlace).

Photos Galería de imágenes

  • Noah Davis añadió más acciones estándar de archivo en Photos al ver una imagen (26.04.0 – enlace).

KPhotoAlbum Software KDE para gestión de imágenes

  • Randall Rude hizo que el extractor de metadatos también extraiga la fecha y hora de creación para videos (enlace).

Aplicaciones creativas

Krita Pintura digital, Libertad creativa

  • Agata Cacko mejoró el rendimiento de la herramienta Liquify Transform haciéndola mucho más fluida (enlace).
  • Agata también añadió un prototipo de herramienta cuchillo a Krita (enlace).
  • Joshua Goins eliminó el cuadro de diálogo de error al cancelar una exportación (enlace).

Utilidades

Konsole Usa la interfaz de línea de comandos

  • Matan Ziv-Av añadió dos acciones de teclado en Konsole para enfocar la siguiente o anterior vista en modo de vista dividida (26.04.0 – enlace).
  • Sune Vuorela añadió una opción para activar o desactivar si Konsole escucha códigos terminales zmodem, que podría ocurrir accidentalmente al enviar un archivo binario (26.04.0 – enlace).

Kate Editor de texto avanzado

  • Héctor Mesa Jiménez añadió configuración predeterminada para netcoredbg, un servidor de depuración independiente para .NET Core (26.04.0 – enlace).

Alligator Lector de feeds RSS

  • Oula V mejoró la función de grupos de feeds de Alligator. Ahora, al crear un grupo, se muestra un error si ya existe otro con el mismo nombre. También limpiaron la lista de grupos (26.04.0 – enlace).
  • Oula también corrigió algunos cierres inesperados tras editar un feed (25.12.0 – enlace) y Stephan Seitz corrigió problemas con la exportación OPML (25.12.0 – enlace).
  • Salvo Tomaselli reordenó los botones del menú, ahora abrir el artículo actual en un navegador externo es el primer botón (25.12.0 – enlace).

Aplicaciones del sistema

Dolphin Gestiona tus archivos

  • Alex Hermann hizo que las aplicaciones basadas en KIO como Dolphin mantengan los permisos de archivos copiados desde un servidor SFTP (enlace 1, enlace 2, enlace 3).

Aplicaciones sociales

NeoChat Chat en Matrix

  • Joshua Goins continuó los esfuerzos para mejorar la Confianza y Seguridad en NeoChat y añadió soporte para reportar salas y usuarios (26.04.0 – enlace).
  • «renner 03» corrigió la integración de KRunner en NeoChat al ejecutar la aplicación en Flatpak (25.12.0 – enlace).

Navegadores

Konqueror Administrador de archivos KDE y navegador web

  • Stefano Crocco añadió una página de configuración para configurar marcadores rápidos en Konqueror. Estos marcadores rápidos son botones que permiten abrir rápidamente enlaces preconfigurados (26.04.0 – enlace).

Falkon Navegador web

  • Juraj Oravec añadió soporte para agregar elementos del menú lateral al API de plugins de Falkon (enlace).

Angelfish Navegador web para dispositivos móviles

  • Rinigus Saar corrigió un problema al recuperar las últimas entradas visitadas (25.12.0 – enlace).

PIM

Trojitá Cliente de correo IMAP

  • Sandøy Hustad comenzó a implementar trabajo para que Trojita soporte Qt 6 (enlace).

Aplicaciones de terceros

Deskflow – Aplicación para compartir teclado y ratón

  • Chris Rizzitello lanzó Deskflow 1.25.0. Los principales cambios son soporte para un icono simbólico en la bandeja que se recolorea correctamente incluso usando el tema Twilight de Plasma; soporte para cambiar el idioma de la aplicación sin reiniciarla; y soporte inicial para el protocolo wl-clipboard de Wayland.

EasyEffect

  • Giusy Digital continuó trabajando en unificar la nomenclatura de las diversas unidades físicas (por ejemplo, dB, Hz, …) en toda la aplicación (enlace).
  • Wellington Wallace portó algunas hojas de superposición a los diálogos Kirigami (enlace).

… Y todo lo demás

Este blog solo cubre la punta del iceberg. Descubre más en el blog de Nate sobre Plasma y su serie This Week in Plasma, donde detalla las novedades del entorno de escritorio Plasma de KDE. Para información sin filtrar, visita KDE’s Planet.

La organización KDE se ha vuelto importante a nivel mundial, y tu tiempo y contribuciones nos han ayudado a llegar hasta aquí. A medida que crecemos, necesitaremos tu apoyo para que KDE sea sostenible.

Puedes ayudar a KDE siendo un miembro activo de la comunidad y participando. Cada colaborador hace una gran diferencia en KDE: no eres un número ni una pieza más en una máquina. ¡Ni siquiera tienes que ser programador! Hay muchas cosas que puedes hacer: ayudar a encontrar y confirmar errores, e incluso quizás solucionarlos; contribuir con diseños para fondos de pantalla, páginas web, iconos e interfaces de aplicaciones; traducir mensajes y elementos de menús a tu idioma; promover KDE en tu comunidad local; y muchas más cosas.

También puedes ayudarnos donando. Cualquier contribución monetaria, por pequeña que sea, nos ayudará a cubrir los costos operativos, salarios, gastos de viaje para los colaboradores y, en general, a que KDE pueda seguir llevando Software Libre al mundo.

Para que tu aplicación sea mencionada aquí, por favor contáctanos en invent o en Matrix.

La entrada Últimas dos semanas en las aplicaciones de KDE se publicó primero en KDE Blog.

a silhouette of a person's head and shoulders, used as a default avatar

Recopilación del boletín de noticias de la Free Software Foundation – diciembre de 2025

Recopilación y traducción del boletín mensual de noticias relacionadas con el software libre publicado por la Free Software Foundation.

¡El boletín de noticias de la FSF está aquí!

La Free Software Foundation (FSF) es una organización creada en Octubre de 1985 por Richard Stallman y otros entusiastas del software libre con el propósito de difundir esta filosofía, frente a las restricciones y abusos a los usuarios por parte del software privativo.

Por cierto este mes se cumplen 40 años de la creación de la FSF.

La Fundación para el software libre (FSF) se dedica a eliminar las restricciones sobre la copia, redistribución, entendimiento, y modificación de programas de computadoras. Con este objeto, promociona el desarrollo y uso del software libre en todas las áreas de la computación, pero muy particularmente, ayudando a desarrollar el sistema operativo GNU.

Mensualmente publican un boletín (supporter) con noticias relacionadas con el software libre, sus campañas, o eventos. Una forma de difundir los proyectos, para que la gente conozca los hechos, se haga su propia opinión, y tomen partido si creen que la reivindicación es justa!!

Puedes ver todos los números publicados en este enlace: http://www.fsf.org/free-software-supporter/free-software-supporter

¿Te gustaría aportar tu ayuda en la traducción y colaborar con la FSF? Lee el siguiente enlace:

Por aquí te traigo un extracto de algunas de las noticias que ha destacado la FSF este mes de diciembre de 2025.

Sólo el software libre permite la soberanía digital

Del 24 de noviembre por la FSFE

El “Germany Stack” es un proyecto central de política digital del gobierno federal alemán. La FSFE pide que Stack se planifique en estrecha coordinación con los socios europeos y se implemente íntegramente como software libre, ya que sólo las cuatro libertades permiten la soberanía digital. Continúe leyendo para obtener más información sobre los detalles de esta solicitud del gobierno federal alemán, incluidos los principios en los que debería basarse el Stack.

El ejército estadounidense quiere arreglar su propio equipo. Los contratistas de defensa están intentando derribarlo.

Del 26 de noviembre por Boone Ashworth

Es probable que las disposiciones sobre el derecho a reparar en la Ley de Autorización de Defensa Nacional, que asegurarían la financiación para el ejército estadounidense en 2026, sean eliminadas del texto final del proyecto de ley a pesar de disfrutar de un amplio apoyo bipartidista, dijeron a WIRED fuentes familiarizadas con las negociaciones en curso.

Dicen que es probable que las disposiciones de la ley que permiten a los militares reparar sus propios equipos se eliminen por completo y se reemplacen con un plan de suscripción de datos como servicio que beneficie a los contratistas de defensa.

Cloudflare caído: la interrupción global afectó a gran parte de Internet

Del 18 de noviembre por Kate O’Flaherty

Aparentemente, la mitad de la red mundial estuvo caída a mediados de noviembre debido a una interrupción de Cloudflare, lo que demuestra que el software privativo no es tan estable y seguro como les gusta afirmar a sus proveedores.

Tantos sitios web que dependen de un único proveedor para servicios de red y seguridad conllevan grandes peligros, tanto para su libertad como para su capacidad de utilizar un programa en el que puede confiar para trabajar. El software libre ciertamente también puede sufrir interrupciones, pero hay muchas más soluciones cuando se utiliza software libre que con software privativo.

Si actualmente utiliza un programa que se vio afectado por la interrupción de Cloudflare (o su lugar de trabajo lo hace), ahora podría ser un buen momento para hablar sobre cambiar a un programa comparable que respete la libertad.

apoyo_fsf

Estas son solo algunas de las noticias recogidas este mes, ¡¡pero hay muchas más muy interesantes!! si quieres leerlas todas (cuando estén traducidas) visita este enlace:

Y todos los números del «supporter» o boletín de noticias de 2025 en español, francés, portugués e inglés aquí:

Support freedom

a silhouette of a person's head and shoulders, used as a default avatar

Congreso esLibre 2026 en Melide

Existen decenas de eventos del Software Libre: Akademy, Gaudec, Akademy-es, talleres de Linux Center, LAS, Flisol, etc. A casi todos les doy promoción en el blog y el de hoy no puede ser una excepción. Os invito a asistir al Congreso esLibre 2026 en Melide, Galicia, un evento que destaca por su apuesta por la Comunidad. Si podéis no os lo perdáis.

Congreso esLibre 2026 en Melide

Los encuentros de desarrolladores y simpatizantes del Software Libre son una de las mejores cosas que suele ofrecer este mundo del conocimiento compartido, y el caso del congreso que promociono por primera vez en el blog no es una excepción.

Se trata de esLibre cuya edición de 2026 se celebrará en Melida (Galicia) el 17 y 18 de abril y que todavía está en la fase de recibir propuestas para charlas… pero date prisa que el plazo finalizará pronto.

En palabras de sus organizadores:

Después de un necesario año sabático por parte de las personas que desarrollan a lo largo del año todas las actividades necesarias, retomamos la edición correspondiente al año 2026 de la mano de la Asociación de usuarios de software libre da Terra de Melide MELISA y del Grupo de Amigos de GNU/Linux de Pontevedra GALPon.

Esta vez tendremos que desplazarnos a Melide una villa de algo más de 8.000 habitantes donde se unen el camino primitivo y el camino francés hacia Santiago, en la provincia de A Coruña y a 53km de Santiago.

Los distintos eventos se realizarán en los espacios socio culturales cedidos por el Concello de Melide concretamente en el Centro Sociocultural Mingos de Pita y en el Edificio Multiusos situados justo al lado uno del otro en la misma Praza das Universidades.

Más información: esLibre 2026 en Melide

La entrada Congreso esLibre 2026 en Melide se publicó primero en KDE Blog.

a silhouette of a person's head and shoulders, used as a default avatar

How to test the syslog-ng Kafka source by building the package yourself?

A long-waited feature for syslog-ng, the Kafka source, is getting ready soon. The development is still in progress, but you can already try it, and it is worth the effort. How? Using the very same tool the syslog-ng testing and release process relies on.

From this blog you can learn how to download and patch syslog-ng git sources and build packages for popular RPM and DEB Linux distributions. Once you have installable packages, comes the fun part: getting the Kafka source working.

Read the rest at https://www.syslog-ng.com/community/b/blog/posts/how-to-test-the-syslog-ng-kafka-source-by-building-the-package-yourself

syslog-ng logo

the avatar of openSUSE News

Intel NPU Driver Now Available in openSUSE Versions

As the founder of the openSUSE Innovator initiative, and a member of the openSUSE and Intel Innovator communities, I maintain my ongoing commitment to bringing cutting-edge technologies to the different flavors of the openSUSE Linux distribution.

With the arrival of NPU (Neural Processing Unit) devices, it has become possible to run LLMs and generative AI applications without relying on a dedicated GPU. In light of this advancement, we began the work of packaging the Intel NPU Driver into RPM for the openSUSE ecosystem. As a result of this collective effort, the openSUSE for Innovators initiative is proud to announce the official availability of this package to the community.

The Intel NPU is an inference accelerator integrated into Intel CPUs starting with the Intel® Core™ Ultra family (formerly known as Meteor Lake). It enables efficient and low-power execution of artificial neural network workloads directly on the processor.

The NPU is integrated into the processor die, designed to perform matrix operations of neural networks with high energy efficiency. Its architecture complements CPU and GPU, enabling intelligent offloading for ONNX models, computer vision pipelines, quantized models, and hybrid model operations with simultaneous use of CPU+GPU+NPU.

Participating in this project is a source of great satisfaction, as we know it will have a significant impact on future applications. As members of an open-source community, we have a responsibility to democratize emerging technologies and help reduce the digital divide, and this delivery is another important step in that direction.

For more information, go to software.opensuse.org!

the avatar of Federico Mena-Quintero

Mutation testing for librsvg

I was reading a blog post about the testing strategy for the Wild linker, when I came upon a link to cargo-mutants, a mutation testing tool for Rust. The tool promised to be easy to set up, so I gave it a try. I'm happy to find that it totally delivers!

Briefly: mutation testing catches cases where bugs are deliberately inserted in the source code, but the test suite fails to catch them: after making the incorrect changes, all the tests still pass. This indicates a gap in the test suite.

Previously I had only seen mentions of "mutation testing" in passing, as something exotic to be done when testing compilers. I don't recall seeing it as a general tool; maybe I have not been looking closely enough.

Setup and running

Setting up cargo-mutants is easy enough: you can cargo install cargo-mutants and run it with cargo mutants.

For librsvg this ran for a few hours, but I discovered a couple of things related to the way the librsvg repository is structured. The repo is a cargo workspace with multiple crates: the librsvg implementation and public Rust API, the rsvg-convert binary, and some utilities like rsvg-bench.

  1. By default cargo-mutants only seemed to pick up the tests for rsvg-convert. I think it may have done this because it is the only binary in the workspace that has a test suite (e.g. rsvg-bench does not have a test suite).

  2. I had to run cargo mutants --package librsvg to tell it to consider the test suite for the librsvg crate, which is the main library. I think I could have used cargo mutants --workspace to make it run all the things; maybe I'll try that next time.

Initial results

My initial run on rsvg-covert produced useful results; cargo-mutants found 32 mutations in the rsvg-convert source code that ought to have caused failures, but the test suite didn't catch them.

The running output of cargo-mutants on the librsvg

The second run, on the librsvg crate, took about 10 hours. It is fascinating to watch it run. In the end it found 889 mutations with bugs that the test suite couldn't catch:

5243 mutants tested in 9h 53m 15s: 889 missed, 3663 caught, 674 unviable, 17 timeouts

What does that mean?

  • 5243 mutants tested: how many modifications were tried on the code.

  • 889 missed: The important ones: after a modification was made, the test suite failed to catch this modification.

  • 3663 caught: Good! The test suite caught these!

  • 674 unviable: These modifications didn't compile. Nothing to do.

  • 17 timeouts: Worth investigating; maybe a function can be marked to be skipped for mutation.

Starting to analyze the results

Due to the way cargo-mutants works, the "missed" results come in an arbitrary order, spread among all the source files:

rsvg/src/path_parser.rs:857:9: replace <impl fmt::Display for ParseError>::fmt -> fmt::Result with Ok(Default::default())
rsvg/src/drawing_ctx.rs:732:33: replace > with == in DrawingCtx::check_layer_nesting_depth
rsvg/src/filters/lighting.rs:931:16: replace / with * in Normal::bottom_left
rsvg/src/test_utils/compare_surfaces.rs:24:9: replace <impl fmt::Display for BufferDiff>::fmt -> fmt::Result with Ok(Default::default())
rsvg/src/filters/turbulence.rs:133:22: replace - with / in setup_seed
rsvg/src/document.rs:627:24: replace match guard is_mime_type(x, "image", "svg+xml") with false in ResourceType::from
rsvg/src/length.rs:472:57: replace * with + in CssLength<N, V>::to_points

So, I started by sorting the missed.txt file from the results. This is much better:

rsvg/src/accept_language.rs:136:9: replace AcceptLanguage::any_matches -> bool with false
rsvg/src/accept_language.rs:136:9: replace AcceptLanguage::any_matches -> bool with true
rsvg/src/accept_language.rs:78:9: replace <impl fmt::Display for AcceptLanguageError>::fmt -> fmt::Result with Ok(Default::default())
rsvg/src/angle.rs:40:22: replace < with <= in Angle::bisect
rsvg/src/angle.rs:41:56: replace - with + in Angle::bisect
rsvg/src/angle.rs:49:35: replace + with - in Angle::flip
rsvg/src/angle.rs:57:23: replace < with <= in Angle::normalize

With the sorted results, I can clearly see how cargo-mutants gradually does its modifications on (say) all the arithmetic and logic operators to try to find changes that would not be caught by the test suite.

Look at the first two lines from above, the ones that refer to AcceptLanguage::any_matches:

rsvg/src/accept_language.rs:136:9: replace AcceptLanguage::any_matches -> bool with false
rsvg/src/accept_language.rs:136:9: replace AcceptLanguage::any_matches -> bool with true

Now look at the corresponding lines in the source:

... impl AcceptLanguage {
135     fn any_matches(&self, tag: &LanguageTag) -> bool {
136         self.iter().any(|(self_tag, _weight)| tag.matches(self_tag))
137     }
... }
}

The two lines from missed.txt mean that if the body of this any_matches() function were replaced with just true or false, instead of its actual work, there would be no failed tests:

135     fn any_matches(&self, tag: &LanguageTag) -> bool {
136         false // or true, either version wouldn't affect the tests
137     }
}

This is bad! It indicates that the test suite does not check that this function, or the surrounding code, is working correctly. And yet, the test coverage report for those lines shows that they are indeed getting executed by the test suite. What is going on?

I think this is what is happening:

  • The librsvg crate's tests do not have tests for AcceptLanguage::any_matches.
  • The rsvg_convert crate's integration tests do have a test for its --accept-language option, and that is what causes this code to get executed and shown as covered in the coverage report.
  • This run of cargo-mutants was just for the librsvg crate, not for the integrated librsvg plus rsvg_convert.

Getting a bit pedantic with the purpose of tests, rsvg-convert assumes that the underlying librsvg library works correctly. The library advertises support in its API for matching based on AcceptLanguage, even though it doesn't test it internally.

On the other hand, rsvg-convert has a test for its own --accept-language option, in the sense of "did we implement this command-line option correctly", not in the sense of "does librsvg implement the AcceptLanguage functionality correctly".

After adding a little unit test for AcceptLanguage::any_matches in the librsvg crate, we can run cargo-mutants just for that the accept_language.rs file again:

# cargo mutants --package librsvg --file accept_language.rs
Found 37 mutants to test
ok       Unmutated baseline in 24.9s build + 6.1s test
 INFO Auto-set test timeout to 31s
MISSED   rsvg/src/accept_language.rs:78:9: replace <impl fmt::Display for AcceptLanguageError>::fmt -> fmt::Result with Ok(Default::default()) in 4.8s build + 6.5s test
37 mutants tested in 2m 59s: 1 missed, 26 caught, 10 unviable

Great! As expected, we just have 1 missed mutant on that file now. Let's look into it.

The function in question is now <impl fmt::Display for AcceptLanguageError>::fmt, an error formatter for the AcceptLanguageError type:

impl fmt::Display for AcceptLanguageError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::NoElements => write!(f, "no language tags in list"),
            Self::InvalidCharacters => write!(f, "invalid characters in language list"),
            Self::InvalidLanguageTag(e) => write!(f, "invalid language tag: {e}"),
            Self::InvalidWeight => write!(f, "invalid q= weight"),
        }
    }
}

What cargo-mutants means by "replace ... -> fmt::Result with Ok(Default::default()) is that if this function were modified to just be like this:

impl fmt::Display for AcceptLanguageError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        Ok(Default::default())
    }
}

then no tests would catch that. Now, this is just a formatter function; the fmt::Result it returns is just whether the underlying call to write!() succeeded. When cargo-mutants discovers that it can change this function to return Ok(Default::default()) it is because fmt::Result is defined as Result<(), fmt::Error>, which implements Default because the unit type () implements Default.

In librsvg, those AcceptLanguageError errors are just surfaced as strings for rsvg-convert, so that if you give it a command-line argument with an invalid value like --accept-language=foo, it will print the appropriate error. However, rsvg-convert does not make any promises as to the content of error messages, so I think it is acceptable to not test this error formatter — just to make sure it handles all the cases, which is already guaranteed by its match statement. Rationale:

  • There already are tests to ensure that the error codes are computed correctly in the parser for AcceptLanguage; those are the AcceptLanguageError's enumeration variants.

  • There is a test in rsvg-convert's test suite to ensure that it detects invalid language tags and reports them.

For cases like this, cargo-mutants allows marking code to be skipped. After marking this fmt implementation with #[mutants::skip], there are no more missed mutants in accept_language.rs.

Yay!

Understanding the tool

You should absolutely read "using results" in the cargo-mutants documentation, which is very well-written. It gives excellent suggestions for how to deal with missed mutants. Again, these indicate potential gaps in your test suite. The documentation discusses how to think about what to do, and I found it very helpful.

Then you should read about genres of mutants. It tells you the kind of modifications that cargo-mutants does to your code. Apart from changing individual operators to try to compute incorrect results, it also does things like replacing whole function bodies to return a different value instead. What if a function returns Default::default() instead of your carefully computed value? What if a boolean function always returns true? What if a function that returns a HashMap always returns an empty hash table, or one full with the product of all keys and values? That is, do your tests actually check your invariants, or your assumptions about the shape of the results of computations? It is really interesting stuff!

Future work for librsvg

The documentation for cargo-mutants suggests how to use it in CI, to ensure that no uncaught mutants are merged into the code. I will probably investigate this once I have fixed all the missed mutants; this will take me a few weeks at least.

Librsvg already has the gitlab incantation to show test coverage for patches in merge requests, so it would be nice to know if the existing tests, or any new added tests, are missing any conditions in the MR. That can be caught with cargo-mutants.

Hackery relevant to my tests, but not to this article

If you are just reading about mutation testing, you can ignore this section. If you are interested in the practicalities of compilation, read on!

The source code for the librsvg crate uses a bit of conditional compilation to select whether to export functions that are used by the integration tests as well as the crate's internal tests. For example, there is some code for diffing two images, and this is used when comparing the pixel output of rendering an SVG to a reference image. For historical reasons, this code ended up in the main library, so that it can run its own internal tests, but then the rest of the integration tests also use this code to diff images. The librsvg crate exports the "diff two images" functions only if it is being compiled for the integration tests, and it doesn't export them for a normal build of the public API.

Somehow, cargo-mutants didn't understand this, and the integration tests did not build since the cargo feature to select that conditionally-compiled code... wasn't active, or something. I tried enabling it by hand with something like cargo mutants --package librsvg -- --features test-utils but that still didn't work.

So, I hacked up a temporary version of the source tree just for mutation testing, which always exports the functions for diffing images, without conditional compilation. In the future it might be possible to split out that code to a separate crate that is only used where needed and never exported. I am not sure how it would be structured, since that code also depends on librsvg's internal representation of pixel images. Maybe we can move the whole thing out to a separate crate? Stop using Cairo image surfaces as the way to represent pixel images? Who knows!