Index: CKEditor/trunk/_source/core/test.js
===================================================================
--- CKEditor/trunk/_source/core/test.js	(revision 4016)
+++ CKEditor/trunk/_source/core/test.js	(revision 4017)
@@ -70,5 +70,11 @@
 				   || elementOrId.value;    // retrieve from value
 
+		return CKEDITOR.test.fixHtml( html, stripLineBreaks );
+	},
+	
+	fixHtml : function( html, stripLineBreaks )
+	{
 		html = html.toLowerCase();
+
 		if ( stripLineBreaks !== false )
 			html = html.replace( /[\n\r]/g, '' );
@@ -85,9 +91,23 @@
 						if ( attName == 'style' )
 						{
-							// Safari adds some extra space to the end.
-							attValue = attValue.replace( /\s+/g, '' );
+							// Reorganize the style rules so they are sorted by name.
 
-							// IE doesn't add the final ";"
-							attValue = attValue.replace( /([^"';\s])\s*(["']?)$/, '$1;$2' );
+							var rules = [];
+
+							// Push all rules into an Array.
+							attValue.replace( /(?:"| |;|^ )\s*([^ :]+?)\s*:\s*([^;"]+?)\s*(?=;|"|$)/g, function( match, name, value )
+								{
+									rules.push( [ name, value ] );
+								});
+
+							// Sort the Array.
+							rules.sort( sorter );
+
+							// Transform each rule entry into a string name:value.
+							for ( i = 0 ; i < rules.length ; i++ )
+								rules[ i ] = rules[ i ].join( ':' );
+
+							// Join all rules with commas, removing spaces and adding an extra comma to the end.
+							attValue = '"' + rules && ( rules.join( ';' ).replace( /\s+/g, '' ) + ';' );
 						}
 
@@ -107,14 +127,9 @@
 					} );
 
-				attribs.sort( function( a, b )
-					{
-						var nameA = a[ 0 ];
-						var nameB = b[ 0 ];
-						return nameA < nameB ? -1 : nameA > nameB ? 1 : 0;
-					} );
+				attribs.sort( sorter );
 
 				var ret = match.replace( /\s{2,}/g, ' ' );
 
-				for ( var i = 0 ; i < attribs.length ; i++ )
+				for ( i = 0 ; i < attribs.length ; i++ )
 				{
 					ret += ' ' + attribs[i][0] + '=';
@@ -126,4 +141,11 @@
 
 		return html;
+
+		function sorter( a, b )
+		{
+			var nameA = a[ 0 ];
+			var nameB = b[ 0 ];
+			return nameA < nameB ? -1 : nameA > nameB ? 1 : 0;
+		}
 	},
 
Index: CKEditor/trunk/_source/tests/plugins/htmldataprocessor/htmldataprocessor.html
===================================================================
--- CKEditor/trunk/_source/tests/plugins/htmldataprocessor/htmldataprocessor.html	(revision 4016)
+++ CKEditor/trunk/_source/tests/plugins/htmldataprocessor/htmldataprocessor.html	(revision 4017)
@@ -264,4 +264,6 @@
 
 			dataProcessor.writer = new CKEDITOR.htmlParser.basicWriter();
+			dataProcessor.writer.sortAttributes = true;
+
 			var html = getTextAreaValue( '_TEXTAREA_3591_2' );
 			var protectedHtml = dataProcessor.toHtml( html );
@@ -309,4 +311,5 @@
 				dataProcessor = editor.dataProcessor;
 			dataProcessor.writer = new CKEDITOR.htmlParser.basicWriter();
+			dataProcessor.writer.sortAttributes = true;
 
 			assert.areSame( '<p><a href="" name="">emptylink</a></p>',
Index: CKEditor/trunk/_source/tests/plugins/styles/styles.html
===================================================================
--- CKEditor/trunk/_source/tests/plugins/styles/styles.html	(revision 4016)
+++ CKEditor/trunk/_source/tests/plugins/styles/styles.html	(revision 4017)
@@ -325,5 +325,5 @@
 			style.applyToRange( range );
 
-			assert.areSame( '<b lang="pt" style="font-size:11pt;color:red;">this<b style="font-weight:700;"> is some sample text</b></b>', getInnerHtml( '_P1' ), 'First range' );
+			assert.areSame( '<b lang="pt" style="color:red;font-size:11pt;">this<b style="font-weight:700;"> is some sample text</b></b>', getInnerHtml( '_P1' ), 'First range' );
 		},
 
