diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index 703b39eb70..afe84910a1 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -274,6 +274,7 @@ set( FONT_SRCS
 	font/outline_font.cpp
 	font/outline_decomposer.cpp
 	font/fontconfig.cpp
+    font/text_attributes.cpp
 	)
 
 set( COMMON_SRCS
diff --git a/common/eda_text.cpp b/common/eda_text.cpp
index 06e0b5437c..ba276709f7 100644
--- a/common/eda_text.cpp
+++ b/common/eda_text.cpp
@@ -469,7 +469,8 @@ EDA_TEXT::GetRenderCache( const KIFONT::FONT* aFont, const wxString& forResolved
 
             attrs.m_Angle = resolvedAngle;
 
-            font->GetLinesAsGlyphs( &m_render_cache, GetShownText(), GetDrawPos() + aOffset, attrs );
+            font->GetLinesAsGlyphs( &m_render_cache, GetShownText(), GetDrawPos() + aOffset,
+                                    attrs );
             m_render_cache_angle = resolvedAngle;
             m_render_cache_text = forResolvedText;
             m_render_cache_offset = aOffset;
@@ -912,30 +913,20 @@ std::shared_ptr<SHAPE_COMPOUND> EDA_TEXT::GetEffectiveTextShape( bool aTriangula
 
 int EDA_TEXT::Compare( const EDA_TEXT* aOther ) const
 {
-#define EPSILON 2       // Should be enough for rounding errors on calculated items
+    wxCHECK( aOther, 1 );
 
-#define TEST( a, b ) { if( a != b ) return a - b; }
-#define TEST_E( a, b ) { if( abs( a - b ) > EPSILON ) return a - b; }
-#define TEST_PT( a, b ) { TEST_E( a.x, b.x ); TEST_E( a.y, b.y ); }
+    int val = m_attributes.Compare( aOther->m_attributes );
 
-    TEST_PT( m_pos, aOther->m_pos );
+    if( val != 0 )
+        return val;
 
-    TEST_PT( m_attributes.m_Size, aOther->m_attributes.m_Size );
-    TEST_E( m_attributes.m_StrokeWidth, aOther->m_attributes.m_StrokeWidth );
-    TEST( m_attributes.m_Angle.AsDegrees(), aOther->m_attributes.m_Angle.AsDegrees() );
-    TEST( m_attributes.m_LineSpacing, aOther->m_attributes.m_LineSpacing );
+    if( m_pos.x != aOther->m_pos.x )
+        return m_pos.x - aOther->m_pos.x;
 
-    TEST( m_attributes.m_Halign, aOther->m_attributes.m_Halign );
-    TEST( m_attributes.m_Valign, aOther->m_attributes.m_Valign );
-    TEST( m_attributes.m_Italic, aOther->m_attributes.m_Italic );
-    TEST( m_attributes.m_Bold, aOther->m_attributes.m_Bold );
-    TEST( m_attributes.m_Underlined, aOther->m_attributes.m_Underlined );
-    TEST( m_attributes.m_Visible, aOther->m_attributes.m_Visible );
-    TEST( m_attributes.m_Mirrored, aOther->m_attributes.m_Mirrored );
-    TEST( m_attributes.m_Multiline, aOther->m_attributes.m_Multiline );
-    TEST( m_attributes.m_KeepUpright, aOther->m_attributes.m_KeepUpright );
+    if( m_pos.y != aOther->m_pos.y )
+        return m_pos.y - aOther->m_pos.y;
 
-    int val = GetFontName().Cmp( aOther->GetFontName() );
+    val = GetFontName().Cmp( aOther->GetFontName() );
 
     if( val != 0 )
         return val;
diff --git a/common/font/text_attributes.cpp b/common/font/text_attributes.cpp
new file mode 100644
index 0000000000..963a66f7d5
--- /dev/null
+++ b/common/font/text_attributes.cpp
@@ -0,0 +1,135 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2021-2023 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <font/text_attributes.h>
+
+#include <font/outline_font.h>
+
+
+TEXT_ATTRIBUTES::TEXT_ATTRIBUTES( KIFONT::FONT* aFont ) :
+    m_Font( aFont ),
+    m_Halign( GR_TEXT_H_ALIGN_CENTER ),
+    m_Valign( GR_TEXT_V_ALIGN_CENTER ),
+    m_Angle( ANGLE_0 ),
+    m_LineSpacing( 1.0 ),
+    m_StrokeWidth( 0 ),
+    m_Italic( false ),
+    m_Bold( false ),
+    m_Underlined( false ),
+    m_Color( KIGFX::COLOR4D::UNSPECIFIED ),
+    m_Visible( true ),
+    m_Mirrored( false ),
+    m_Multiline( true ),
+    m_KeepUpright( false )
+{
+}
+
+
+int TEXT_ATTRIBUTES::Compare( const TEXT_ATTRIBUTES& aRhs ) const
+{
+    wxString fontName;
+
+    if( m_Font )
+        fontName = m_Font->GetName();
+
+    wxString rhsFontName;
+
+    if( aRhs.m_Font )
+        rhsFontName = aRhs.m_Font->GetName();
+
+    int retv = fontName.Cmp( rhsFontName );
+
+    if( retv )
+        return retv;
+
+    if( m_Size.x != aRhs.m_Size.x )
+        return m_Size.x - aRhs.m_Size.x;
+
+    if( m_Size.y != aRhs.m_Size.y )
+        return m_Size.y - aRhs.m_Size.y;
+
+    if( m_StrokeWidth != aRhs.m_StrokeWidth )
+        return m_StrokeWidth - aRhs.m_StrokeWidth;
+
+    if( m_Angle.AsDegrees() != aRhs.m_Angle.AsDegrees() )
+        return m_Angle.AsDegrees() - aRhs.m_Angle.AsDegrees();
+
+    if( m_LineSpacing != aRhs.m_LineSpacing )
+        return m_LineSpacing - aRhs.m_LineSpacing;
+
+    if( m_Halign != aRhs.m_Halign )
+        return m_Halign - aRhs.m_Halign;
+
+    if( m_Valign != aRhs.m_Valign )
+        return m_Valign - aRhs.m_Valign;
+
+    if( m_Italic != aRhs.m_Italic )
+        return m_Italic - aRhs.m_Italic;
+
+    if( m_Bold != aRhs.m_Bold )
+        return m_Bold - aRhs.m_Bold;
+
+    if( m_Underlined != aRhs.m_Underlined )
+        return m_Underlined - aRhs.m_Underlined;
+
+    retv = m_Color.Compare( aRhs.m_Color );
+
+    if( retv )
+        return retv;
+
+    if( m_Visible != aRhs.m_Visible )
+        return m_Visible - aRhs.m_Visible;
+
+    if( m_Mirrored != aRhs.m_Mirrored )
+        return m_Mirrored - aRhs.m_Mirrored;
+
+    if( m_Multiline != aRhs.m_Multiline )
+        return m_Multiline - aRhs.m_Multiline;
+
+    return m_KeepUpright - aRhs.m_KeepUpright;
+}
+
+
+std::ostream& operator<<( std::ostream& aStream, const TEXT_ATTRIBUTES& aAttributes )
+{
+    aStream << "Font: \"";
+
+    if ( aAttributes.m_Font )
+        aStream << *aAttributes.m_Font;
+    else
+        aStream << "UNDEFINED";
+
+    aStream << "\"\n";
+    aStream << "Horizontal Alignment: " << aAttributes.m_Halign << std::endl
+            << "Vertical Alignment: " << aAttributes.m_Valign << std::endl
+            << "Angle: " << aAttributes.m_Angle << std::endl
+            << "Line Spacing: " << aAttributes.m_LineSpacing << std::endl
+            << "Stroke Width: " << aAttributes.m_StrokeWidth << std::endl
+            << "Italic: " << aAttributes.m_Italic << std::endl
+            << "Bold: " << aAttributes.m_Bold << std::endl
+            << "Underline: " << aAttributes.m_Underlined << std::endl
+            << "Color: " << aAttributes.m_Color << std::endl
+            << "Visible " << aAttributes.m_Visible << std::endl
+            << "Mirrored " << aAttributes.m_Mirrored << std::endl
+            << "Multilined: " << aAttributes.m_Multiline << std::endl
+            << "Size: " << aAttributes.m_Size << std::endl
+            << "Keep Upright: " << aAttributes.m_KeepUpright << std::endl;
+
+    return aStream;
+}
diff --git a/common/gal/color4d.cpp b/common/gal/color4d.cpp
index fea282d3e5..937d4a428c 100644
--- a/common/gal/color4d.cpp
+++ b/common/gal/color4d.cpp
@@ -2,7 +2,7 @@
  * This program source code file is part of KICAD, a free EDA CAD application.
  *
  * Copyright 2012 Torsten Hueter, torstenhtr <at> gmx.de
- * Copyright 2017-2021 Kicad Developers, see AUTHORS.txt for contributors.
+ * Copyright 2017-2023 Kicad Developers, see AUTHORS.txt for contributors.
  *
  *
  * This program is free software; you can redistribute it and/or
@@ -582,3 +582,21 @@ COLOR4D& COLOR4D::FromCSSRGBA( int aRed, int aGreen, int aBlue, double aAlpha )
 
     return *this;
 }
+
+
+int COLOR4D::Compare( const COLOR4D& aRhs ) const
+{
+    if( r != aRhs.r )
+        return ( r < aRhs.r ) ? -1 : 1;
+
+    if( g != aRhs.g )
+        return ( g < aRhs.g ) ? -1 : 1;
+
+    if( b != aRhs.b )
+        return ( b < aRhs.b ) ? -1 : 1;
+
+    if( a != aRhs.a )
+        return ( a < aRhs.a ) ? -1 : 1;
+
+    return 0;
+}
diff --git a/eeschema/netlist_exporters/netlist_exporter_spice.cpp b/eeschema/netlist_exporters/netlist_exporter_spice.cpp
index ba3f6ba436..f939d739e4 100644
--- a/eeschema/netlist_exporters/netlist_exporter_spice.cpp
+++ b/eeschema/netlist_exporters/netlist_exporter_spice.cpp
@@ -47,6 +47,7 @@
 #include <fmt/core.h>
 #include <paths.h>
 #include <wx/dir.h>
+#include <wx/log.h>
 #include <locale_io.h>
 #include "markup_parser.h"
 
diff --git a/eeschema/sch_plotter.cpp b/eeschema/sch_plotter.cpp
index 389beebb2d..1cd5198761 100644
--- a/eeschema/sch_plotter.cpp
+++ b/eeschema/sch_plotter.cpp
@@ -4,7 +4,7 @@
  * Copyright (C) 1992-2018 Jean-Pierre Charras jp.charras at wanadoo.fr
  * Copyright (C) 1992-2010 Lorenzo Marcantonio
  * Copyright (C) 2011 Wayne Stambaugh <stambaughw@gmail.com>
- * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -24,6 +24,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
  */
 
+#include <wx/log.h>
 #include <common.h>
 #include <sch_plotter.h>
 #include <locale_io.h>
@@ -1069,4 +1070,4 @@ void SCH_PLOTTER::Plot( PLOT_FORMAT aPlotFormat, const SCH_PLOT_SETTINGS& aPlotS
     case PLOT_FORMAT::SVG: createSVGFiles( aPlotSettings, aRenderSettings, aReporter ); break;
     case PLOT_FORMAT::HPGL: createHPGLFiles( aPlotSettings, aRenderSettings, aReporter ); break;
     }
-}
\ No newline at end of file
+}
diff --git a/eeschema/sch_plugins/database/sch_database_plugin.cpp b/eeschema/sch_plugins/database/sch_database_plugin.cpp
index 4ebc7d03e7..7ea8f5de5a 100644
--- a/eeschema/sch_plugins/database/sch_database_plugin.cpp
+++ b/eeschema/sch_plugins/database/sch_database_plugin.cpp
@@ -20,6 +20,7 @@
 
 #include <iostream>
 #include <unordered_set>
+#include <wx/log.h>
 
 #include <boost/algorithm/string.hpp>
 
diff --git a/eeschema/sch_plugins/kicad/sch_sexpr_lib_plugin_cache.cpp b/eeschema/sch_plugins/kicad/sch_sexpr_lib_plugin_cache.cpp
index 16635ace01..2ef8d8001f 100644
--- a/eeschema/sch_plugins/kicad/sch_sexpr_lib_plugin_cache.cpp
+++ b/eeschema/sch_plugins/kicad/sch_sexpr_lib_plugin_cache.cpp
@@ -19,6 +19,7 @@
  * with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <wx/log.h>
 #include <base_units.h>
 #include <lib_shape.h>
 #include <lib_symbol.h>
diff --git a/eeschema/sim/spice_model_parser.cpp b/eeschema/sim/spice_model_parser.cpp
index 76c242d9a0..aa243f1be5 100644
--- a/eeschema/sim/spice_model_parser.cpp
+++ b/eeschema/sim/spice_model_parser.cpp
@@ -22,6 +22,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
  */
 
+#include <wx/log.h>
 #include <sim/spice_model_parser.h>
 #include <sim/spice_grammar.h>
 #include <sim/sim_model_spice.h>
diff --git a/eeschema/tools/sch_move_tool.cpp b/eeschema/tools/sch_move_tool.cpp
index 0760c210de..a64bc4e33e 100644
--- a/eeschema/tools/sch_move_tool.cpp
+++ b/eeschema/tools/sch_move_tool.cpp
@@ -23,6 +23,7 @@
  */
 
 #include <cmath>
+#include <wx/log.h>
 #include <trigo.h>
 #include <tool/tool_manager.h>
 #include <tools/ee_grid_helper.h>
diff --git a/include/font/text_attributes.h b/include/font/text_attributes.h
index 7a43820dab..c7c5655a52 100644
--- a/include/font/text_attributes.h
+++ b/include/font/text_attributes.h
@@ -2,7 +2,7 @@
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
  * Copyright (C) 2021 Ola Rinta-Koski
- * Copyright (C) 2021-2022 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 2021-2023 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software: you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -21,14 +21,10 @@
 #ifndef TEXT_ATTRIBUTES_H
 #define TEXT_ATTRIBUTES_H
 
-#include <iostream>
-#include <wx/log.h>
-#include <cmath>
 #include <math/vector2d.h>
 #include <gal/color4d.h>
 #include "../../libs/kimath/include/geometry/eda_angle.h"
 
-class EDA_TEXT;
 
 namespace KIFONT
 {
@@ -63,26 +59,37 @@ enum GR_TEXT_V_ALIGN_T
 class TEXT_ATTRIBUTES
 {
 public:
-    KIFONT::FONT*     m_Font = nullptr;
-    GR_TEXT_H_ALIGN_T m_Halign = GR_TEXT_H_ALIGN_CENTER;
-    GR_TEXT_V_ALIGN_T m_Valign = GR_TEXT_V_ALIGN_CENTER;
-    EDA_ANGLE         m_Angle = ANGLE_0;
-    double            m_LineSpacing = 1.0;
-    int               m_StrokeWidth = 0;
-    bool              m_Italic = false;
-    bool              m_Bold = false;
-    bool              m_Underlined = false;
-    KIGFX::COLOR4D    m_Color = KIGFX::COLOR4D::UNSPECIFIED;
-    bool              m_Visible = true;
-    bool              m_Mirrored = false;
-    bool              m_Multiline = true;
+    TEXT_ATTRIBUTES( KIFONT::FONT* aFont = nullptr );
+
+    int Compare( const TEXT_ATTRIBUTES& aRhs ) const;
+
+    bool operator==( const TEXT_ATTRIBUTES& aRhs ) const { return Compare( aRhs ) == 0; }
+    bool operator>( const TEXT_ATTRIBUTES& aRhs ) const { return Compare( aRhs ) > 0; }
+    bool operator<( const TEXT_ATTRIBUTES& aRhs ) const { return Compare( aRhs ) < 0; }
+
+    KIFONT::FONT*     m_Font;
+    GR_TEXT_H_ALIGN_T m_Halign;
+    GR_TEXT_V_ALIGN_T m_Valign;
+    EDA_ANGLE         m_Angle;
+    double            m_LineSpacing;
+    int               m_StrokeWidth;
+    bool              m_Italic;
+    bool              m_Bold;
+    bool              m_Underlined;
+    KIGFX::COLOR4D    m_Color;
+    bool              m_Visible;
+    bool              m_Mirrored;
+    bool              m_Multiline;
     VECTOR2I          m_Size;
 
     /**
      * If true, keep rotation angle between -90...90 degrees for readability
      */
-    bool              m_KeepUpright = false;
+    bool              m_KeepUpright;
 };
 
 
+extern std::ostream& operator<<( std::ostream& aStream, const TEXT_ATTRIBUTES& aAttributes );
+
+
 #endif //TEXT_ATTRIBUTES_H
diff --git a/include/gal/color4d.h b/include/gal/color4d.h
index 36e1ea6438..f84969db9e 100644
--- a/include/gal/color4d.h
+++ b/include/gal/color4d.h
@@ -2,7 +2,7 @@
  * This program source code file is part of KICAD, a free EDA CAD application.
  *
  * Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
- * Copyright (C) 2017-2020 Kicad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 2017-2023 Kicad Developers, see AUTHORS.txt for contributors.
  *
  * Color class
  *
@@ -363,6 +363,8 @@ public:
      */
     double Distance( const COLOR4D& other ) const;
 
+    int Compare( const COLOR4D& aRhs ) const;
+
     /**
      * Returns a legacy color ID that is closest to the given 8-bit RGB values.
      */
diff --git a/pagelayout_editor/tools/pl_edit_tool.cpp b/pagelayout_editor/tools/pl_edit_tool.cpp
index 101568f4ca..ba50dca18a 100644
--- a/pagelayout_editor/tools/pl_edit_tool.cpp
+++ b/pagelayout_editor/tools/pl_edit_tool.cpp
@@ -22,6 +22,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
  */
 
+#include <wx/log.h>
 #include <fmt/format.h>
 
 #include <tool/tool_manager.h>
diff --git a/pagelayout_editor/tools/pl_point_editor.cpp b/pagelayout_editor/tools/pl_point_editor.cpp
index 11a91db353..a437d8ba2e 100644
--- a/pagelayout_editor/tools/pl_point_editor.cpp
+++ b/pagelayout_editor/tools/pl_point_editor.cpp
@@ -25,6 +25,7 @@
 #include <functional>
 using namespace std::placeholders;
 
+#include <wx/log.h>
 #include <fmt/format.h>
 
 #include <tool/tool_manager.h>
diff --git a/pcbnew/exporters/step/exporter_step.cpp b/pcbnew/exporters/step/exporter_step.cpp
index 45f578a5e9..742faadc04 100644
--- a/pcbnew/exporters/step/exporter_step.cpp
+++ b/pcbnew/exporters/step/exporter_step.cpp
@@ -45,6 +45,7 @@
 #include <Standard_Version.hxx>
 
 #include <wx/crt.h>
+#include <wx/log.h>
 
 #define OCC_VERSION_MIN 0x070500
 
diff --git a/pcbnew/pcb_expr_functions.cpp b/pcbnew/pcb_expr_functions.cpp
index 018caab8bb..16240420d1 100644
--- a/pcbnew/pcb_expr_functions.cpp
+++ b/pcbnew/pcb_expr_functions.cpp
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2019-2022 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 2019-2023 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -24,6 +24,7 @@
 
 #include <cstdio>
 #include <memory>
+#include <wx/log.h>
 #include <board.h>
 #include <board_design_settings.h>
 #include <drc/drc_rtree.h>
diff --git a/pcbnew/pcbplot.h b/pcbnew/pcbplot.h
index d01ed6ad9c..61e67b69ab 100644
--- a/pcbnew/pcbplot.h
+++ b/pcbnew/pcbplot.h
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -30,6 +30,7 @@
 #include <settings/settings_manager.h>
 #include <board_item.h>
 
+class EDA_TEXT;
 class PLOTTER;
 class PCB_TEXT;
 class PAD;
diff --git a/pcbnew/plot_board_layers.cpp b/pcbnew/plot_board_layers.cpp
index 4b475e99c2..98aca8848d 100644
--- a/pcbnew/plot_board_layers.cpp
+++ b/pcbnew/plot_board_layers.cpp
@@ -29,6 +29,7 @@
  */
 
 
+#include <wx/log.h>
 #include <eda_item.h>
 #include <layer_ids.h>
 #include <geometry/geometry_utils.h>
diff --git a/pcbnew/plugins/legacy/legacy_plugin.cpp b/pcbnew/plugins/legacy/legacy_plugin.cpp
index b82395a512..d1fb96cfff 100644
--- a/pcbnew/plugins/legacy/legacy_plugin.cpp
+++ b/pcbnew/plugins/legacy/legacy_plugin.cpp
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2007-2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  * Copyright (C) 2019 Jean-Pierre Charras, jp.charras@wanadoo.fr
- * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -63,6 +63,7 @@
 #include <cstring>
 #include <plugins/legacy/legacy_plugin.h>   // implement this here
 #include <wx/ffile.h>
+#include <wx/log.h>
 #include <wx/string.h>
 
 #include <string_utils.h>
diff --git a/pcbnew/router/pns_kicad_iface.h b/pcbnew/router/pns_kicad_iface.h
index 6148cc95c2..0bb489f32d 100644
--- a/pcbnew/router/pns_kicad_iface.h
+++ b/pcbnew/router/pns_kicad_iface.h
@@ -2,7 +2,7 @@
  * KiRouter - a push-and-(sometimes-)shove PCB router
  *
  * Copyright (C) 2013-2016 CERN
- * Copyright (C) 2016-2021 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 2016-2023 KiCad Developers, see AUTHORS.txt for contributors.
  * Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
  *
  * This program is free software: you can redistribute it and/or modify it
@@ -31,6 +31,7 @@ class PNS_PCBNEW_DEBUG_DECORATOR;
 
 class BOARD;
 class BOARD_COMMIT;
+class EDA_TEXT;
 class PCB_DISPLAY_OPTIONS;
 class PCB_TOOL_BASE;
 class FOOTPRINT;
diff --git a/qa/unittests/common/CMakeLists.txt b/qa/unittests/common/CMakeLists.txt
index f61871bd13..3aa2c5046f 100644
--- a/qa/unittests/common/CMakeLists.txt
+++ b/qa/unittests/common/CMakeLists.txt
@@ -1,6 +1,6 @@
 # This program source code file is part of KiCad, a free EDA CAD application.
 #
-# Copyright (C) 2018 KiCad Developers, see CHANGELOG.TXT for contributors.
+# Copyright (C) 2018, 2023 KiCad Developers, see CHANGELOG.TXT for contributors.
 #
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
@@ -42,6 +42,7 @@ set( QA_COMMON_SRCS
     test_kiid.cpp
     test_property.cpp
     test_refdes_utils.cpp
+    test_text_attributes.cpp
     test_title_block.cpp
     test_types.cpp
     test_utf8.cpp
@@ -65,7 +66,8 @@ endif()
 
 if( WIN32 )
     # We want to declare a resource manifest on Windows to enable UTF8 mode
-    # Without UTF8 mode, some random IO tests may fail, we set the active code page on normal kicad to UTF8 as well
+    # Without UTF8 mode, some random IO tests may fail, we set the active code page on
+    # normal kicad to UTF8 as well
     if( MINGW )
         # QA_COMMON_RESOURCES variable is set by the macro.
         mingw_resource_compiler( qa_common )
diff --git a/qa/unittests/common/test_color4d.cpp b/qa/unittests/common/test_color4d.cpp
index bd758d1c02..722cf4fb78 100644
--- a/qa/unittests/common/test_color4d.cpp
+++ b/qa/unittests/common/test_color4d.cpp
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2018-2019 KiCad Developers, see AUTHORS.TXT for contributors.
+ * Copyright (C) 2018-2019, 2023 KiCad Developers, see AUTHORS.TXT for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -305,4 +305,44 @@ BOOST_AUTO_TEST_CASE( FromWx )
     }
 }
 
+
+/**
+ * Check the Compare method.
+ */
+BOOST_AUTO_TEST_CASE( Compare )
+{
+    COLOR4D a( 0.5, 0.5, 0.5, 0.5 );
+    COLOR4D b( 0.5, 0.5, 0.5, 0.5 );
+
+    BOOST_CHECK_EQUAL( a.Compare( b ), 0 );
+
+    b.r = 0.25;
+    BOOST_CHECK_GT( a.Compare( b ), 0 );
+
+    b.r = 0.75;
+    BOOST_CHECK_LT( a.Compare( b ), 0 );
+
+    b.r = 0.5;
+    b.g = 0.25;
+    BOOST_CHECK_GT( a.Compare( b ), 0 );
+
+    b.g = 0.75;
+    BOOST_CHECK_LT( a.Compare( b ), 0 );
+
+    b.g = 0.5;
+    b.b = 0.25;
+    BOOST_CHECK_GT( a.Compare( b ), 0 );
+
+    b.b = 0.75;
+    BOOST_CHECK_LT( a.Compare( b ), 0 );
+
+    b.b = 0.5;
+    b.a = 0.25;
+    BOOST_CHECK_GT( a.Compare( b ), 0 );
+
+    b.a = 0.75;
+    BOOST_CHECK_LT( a.Compare( b ), 0 );
+}
+
+
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/qa/unittests/common/test_text_attributes.cpp b/qa/unittests/common/test_text_attributes.cpp
new file mode 100644
index 0000000000..d5ebb42c90
--- /dev/null
+++ b/qa/unittests/common/test_text_attributes.cpp
@@ -0,0 +1,152 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2023 Wayne Stambaugh <stambaughw@gmail.com>
+ * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <qa_utils/wx_utils/unit_test_utils.h>
+
+#include <font/text_attributes.h>
+#include <font/font.h>
+
+
+BOOST_AUTO_TEST_SUITE( TextAttributes )
+
+
+BOOST_AUTO_TEST_CASE( Compare )
+{
+    TEXT_ATTRIBUTES a;
+    TEXT_ATTRIBUTES b;
+
+    BOOST_CHECK_EQUAL( a, b );
+
+    a.m_Font = KIFONT::FONT::GetFont();
+    BOOST_CHECK_GT( a, b );
+
+    a.m_Font = nullptr;
+    b.m_Font = KIFONT::FONT::GetFont();
+    BOOST_CHECK_LT( a, b );
+
+    b.m_Font = nullptr;
+    a.m_Halign = GR_TEXT_H_ALIGN_RIGHT;
+    BOOST_CHECK_GT( a, b );
+
+    a.m_Halign = GR_TEXT_H_ALIGN_CENTER;
+    b.m_Halign = GR_TEXT_H_ALIGN_RIGHT;
+    BOOST_CHECK_LT( a, b );
+
+    b.m_Halign = GR_TEXT_H_ALIGN_CENTER;
+    a.m_Valign = GR_TEXT_V_ALIGN_BOTTOM;
+    BOOST_CHECK_GT( a, b );
+
+    a.m_Valign = GR_TEXT_V_ALIGN_CENTER;
+    b.m_Valign = GR_TEXT_V_ALIGN_BOTTOM;
+    BOOST_CHECK_LT( a, b );
+
+    b.m_Valign = GR_TEXT_V_ALIGN_CENTER;
+    a.m_Angle = EDA_ANGLE( 90.0, DEGREES_T );
+    BOOST_CHECK_GT( a, b );
+
+    a.m_Angle = EDA_ANGLE( 0.0, DEGREES_T );
+    b.m_Angle = EDA_ANGLE( 90.0, DEGREES_T );
+    BOOST_CHECK_LT( a, b );
+
+    b.m_Angle = EDA_ANGLE( 0.0, DEGREES_T );
+    a.m_StrokeWidth = 1;
+    BOOST_CHECK_GT( a, b );
+
+    a.m_StrokeWidth = 0;
+    b.m_StrokeWidth = 1;
+    BOOST_CHECK_LT( a, b );
+
+    b.m_StrokeWidth = 0;
+    a.m_Italic = true;
+    BOOST_CHECK_GT( a, b );
+
+    a.m_Italic = false;
+    b.m_Italic = true;
+    BOOST_CHECK_LT( a, b );
+
+    b.m_Italic = false;
+    a.m_Bold = true;
+    BOOST_CHECK_GT( a, b );
+
+    a.m_Bold = false;
+    b.m_Bold = true;
+    BOOST_CHECK_LT( a, b );
+
+    b.m_Bold = false;
+    a.m_Underlined = true;
+    BOOST_CHECK_GT( a, b );
+
+    a.m_Underlined = false;
+    b.m_Underlined = true;
+    BOOST_CHECK_LT( a, b );
+
+    b.m_Underlined = false;
+    a.m_Color = KIGFX::COLOR4D( RED );
+    BOOST_CHECK_GT( a, b );
+
+    a.m_Color = KIGFX::COLOR4D( UNSPECIFIED_COLOR );
+    b.m_Color = KIGFX::COLOR4D( RED );
+    BOOST_CHECK_LT( a, b );
+
+    b.m_Color = KIGFX::COLOR4D( UNSPECIFIED_COLOR );
+    b.m_Visible = false;
+    BOOST_CHECK_GT( a, b );
+
+    b.m_Visible = true;
+    a.m_Visible = false;
+    BOOST_CHECK_LT( a, b );
+
+    a.m_Visible = true;
+    a.m_Mirrored = true;
+    BOOST_CHECK_GT( a, b );
+
+    a.m_Mirrored = false;
+    b.m_Mirrored = true;
+    BOOST_CHECK_LT( a, b );
+
+    b.m_Mirrored = false;
+    b.m_Multiline = false;
+    BOOST_CHECK_GT( a, b );
+
+    b.m_Multiline = true;
+    a.m_Multiline = false;
+    BOOST_CHECK_LT( a, b );
+
+    a.m_Multiline = true;
+    a.m_Size.x = 1;
+    BOOST_CHECK_GT( a, b );
+
+    a.m_Size.x = 0;
+    b.m_Size.x = 1;
+    BOOST_CHECK_LT( a, b );
+
+    b.m_Size.x = 0;
+    a.m_KeepUpright = true;
+    BOOST_CHECK_GT( a, b );
+
+    a.m_KeepUpright = false;
+    b.m_KeepUpright = true;
+    BOOST_CHECK_LT( a, b );
+
+    b.m_KeepUpright = false;
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/qa/unittests/eeschema/test_netlist_exporter_spice.h b/qa/unittests/eeschema/test_netlist_exporter_spice.h
index ac52f3fc1c..1524df2cee 100644
--- a/qa/unittests/eeschema/test_netlist_exporter_spice.h
+++ b/qa/unittests/eeschema/test_netlist_exporter_spice.h
@@ -21,6 +21,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
  */
 
+#include <wx/log.h>
 #include <qa_utils/wx_utils/unit_test_utils.h>
 #include <boost/test/results_collector.hpp> // To check if the current test failed (to be moved?).
 #include <eeschema_test_utils.h>