diff --git a/HTMLKit.xcodeproj/project.pbxproj b/HTMLKit.xcodeproj/project.pbxproj
index f1cd70e..f4e0e6f 100644
--- a/HTMLKit.xcodeproj/project.pbxproj
+++ b/HTMLKit.xcodeproj/project.pbxproj
@@ -78,6 +78,10 @@
62491C471AFE51F100ACF9E2 /* CSSLexer.c in Sources */ = {isa = PBXBuildFile; fileRef = 62491C451AFE51F100ACF9E2 /* CSSLexer.c */; };
62491C481AFE51F100ACF9E2 /* CSSLexer.c in Sources */ = {isa = PBXBuildFile; fileRef = 62491C451AFE51F100ACF9E2 /* CSSLexer.c */; };
62491C491AFE51F100ACF9E2 /* CSSLexer.h in Headers */ = {isa = PBXBuildFile; fileRef = 62491C461AFE51F100ACF9E2 /* CSSLexer.h */; };
+ 624AB3171B0508AE00F3830D /* CSSTypeSelectorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624AB3161B0508AE00F3830D /* CSSTypeSelectorTests.m */; };
+ 624AB3181B0508AE00F3830D /* CSSTypeSelectorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624AB3161B0508AE00F3830D /* CSSTypeSelectorTests.m */; };
+ 624AB31A1B050A4D00F3830D /* CSSAttributeSelectorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624AB3191B050A4D00F3830D /* CSSAttributeSelectorTests.m */; };
+ 624AB31B1B050A4D00F3830D /* CSSAttributeSelectorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624AB3191B050A4D00F3830D /* CSSAttributeSelectorTests.m */; };
624AC8FF19FBF59800BD3C4A /* HTMLTokens.h in Headers */ = {isa = PBXBuildFile; fileRef = 624AC8FE19FBF4F700BD3C4A /* HTMLTokens.h */; };
624AC90119FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624AC90019FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m */; };
624AC90219FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624AC90019FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m */; };
@@ -238,6 +242,8 @@
62491C451AFE51F100ACF9E2 /* CSSLexer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CSSLexer.c; sourceTree = ""; };
62491C461AFE51F100ACF9E2 /* CSSLexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSLexer.h; sourceTree = ""; };
624AB3151B04EA4200F3830D /* CSSSelectors.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSSSelectors.h; sourceTree = ""; };
+ 624AB3161B0508AE00F3830D /* CSSTypeSelectorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSTypeSelectorTests.m; sourceTree = ""; };
+ 624AB3191B050A4D00F3830D /* CSSAttributeSelectorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSAttributeSelectorTests.m; sourceTree = ""; };
624AC8FE19FBF4F700BD3C4A /* HTMLTokens.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLTokens.h; sourceTree = ""; };
624AC90019FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitTokenizerTests.m; sourceTree = ""; };
624AC90419FBFE8A00BD3C4A /* html5lib-tests */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "html5lib-tests"; sourceTree = ""; };
@@ -501,6 +507,8 @@
624B9FB71AE072CB00646C4C /* Nodes */,
624B9FB81AE072D500646C4C /* Categories */,
625A14CB19C7829400AD0C32 /* Supporting Files */,
+ 624AB3161B0508AE00F3830D /* CSSTypeSelectorTests.m */,
+ 624AB3191B050A4D00F3830D /* CSSAttributeSelectorTests.m */,
);
name = Tests;
path = HTMLKitTests;
@@ -828,7 +836,9 @@
6239755B1AC362CA007E26F1 /* HTMLKitTreeConstructionTests.m in Sources */,
623CAF9E1AD88BEA00E34C32 /* HTMLKitParserPerformance.m in Sources */,
62EC7AE71AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m in Sources */,
+ 624AB31B1B050A4D00F3830D /* CSSAttributeSelectorTests.m in Sources */,
624B9FB61AE0391400646C4C /* HTMLKitOrderedDictionaryTests.m in Sources */,
+ 624AB3181B0508AE00F3830D /* CSSTypeSelectorTests.m in Sources */,
6236738F1AC0CE2500FF89B3 /* HTMLKitTokenizerPerformance.m in Sources */,
624AC90219FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m in Sources */,
624B9FB31AE0313300646C4C /* HTMLKitStringCategoryTests.m in Sources */,
@@ -886,7 +896,9 @@
6239755A1AC362CA007E26F1 /* HTMLKitTreeConstructionTests.m in Sources */,
623CAF9D1AD88BEA00E34C32 /* HTMLKitParserPerformance.m in Sources */,
62EC7AE61AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m in Sources */,
+ 624AB31A1B050A4D00F3830D /* CSSAttributeSelectorTests.m in Sources */,
624B9FB51AE0391400646C4C /* HTMLKitOrderedDictionaryTests.m in Sources */,
+ 624AB3171B0508AE00F3830D /* CSSTypeSelectorTests.m in Sources */,
6236738E1AC0CE2500FF89B3 /* HTMLKitTokenizerPerformance.m in Sources */,
624AC90119FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m in Sources */,
624B9FB21AE0313300646C4C /* HTMLKitStringCategoryTests.m in Sources */,
diff --git a/HTMLKit/CSSSelectors.h b/HTMLKit/CSSSelectors.h
index fd583d6..30d21f3 100644
--- a/HTMLKit/CSSSelectors.h
+++ b/HTMLKit/CSSSelectors.h
@@ -6,8 +6,6 @@
// Copyright (c) 2015 BrainCookie. All rights reserved.
//
-#ifndef HTMLKit_CSSSelectors_h
-#define HTMLKit_CSSSelectors_h
-
-
-#endif
+#import "CSSSelector.h"
+#import "CSSTypeSelector.h"
+#import "CSSAttributeSelector.h"
diff --git a/HTMLKitTests/CSSAttributeSelectorTests.m b/HTMLKitTests/CSSAttributeSelectorTests.m
new file mode 100644
index 0000000..2b8357e
--- /dev/null
+++ b/HTMLKitTests/CSSAttributeSelectorTests.m
@@ -0,0 +1,210 @@
+//
+// CSSAttributeSelectorTests.m
+// HTMLKit
+//
+// Created by Iska on 14/05/15.
+// Copyright (c) 2015 BrainCookie. All rights reserved.
+//
+
+#import
+#import "CSSSelectors.h"
+#import "HTMLNodes.h"
+
+@interface CSSAttributeSelectorTests : XCTestCase
+{
+ HTMLElement *_element;
+}
+@end
+
+@implementation CSSAttributeSelectorTests
+
+- (void)setUp
+{
+ [super setUp];
+ _element = [[HTMLElement alloc] initWithTagName:@"div"];
+}
+
+- (void)testAttributeExists
+{
+ CSSAttributeSelector *selector = [[CSSAttributeSelector alloc] initWithType:CSSAttributeSelectorExists
+ attributeName:@"attr"
+ attrbiuteValue:@""];
+
+ XCTAssertFalse([selector acceptNode:_element]);
+
+ _element[@"class"] = @"class";
+ XCTAssertFalse([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"value";
+ XCTAssertTrue([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"value 2";
+ XCTAssertTrue([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"value 3";
+ XCTAssertTrue([selector acceptNode:_element]);
+
+ [_element.attributes removeObjectForKey:@"attr"];
+ XCTAssertFalse([selector acceptNode:_element]);
+}
+
+- (void)testAttributeExactMatch
+{
+ CSSAttributeSelector *selector = [[CSSAttributeSelector alloc] initWithType:CSSAttributeSelectorExactMatch
+ attributeName:@"attr"
+ attrbiuteValue:@"value"];
+
+ XCTAssertFalse([selector acceptNode:_element]);
+
+ _element[@"class"] = @"class";
+ XCTAssertFalse([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"value 1";
+ XCTAssertFalse([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"value 2";
+ XCTAssertFalse([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"value 3";
+ XCTAssertFalse([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"value";
+ XCTAssertTrue([selector acceptNode:_element]);
+
+ [_element.attributes removeObjectForKey:@"attr"];
+ XCTAssertFalse([selector acceptNode:_element]);
+}
+
+- (void)testAttributeIncludes
+{
+ CSSAttributeSelector *selector = [[CSSAttributeSelector alloc] initWithType:CSSAttributeSelectorIncludes
+ attributeName:@"attr"
+ attrbiuteValue:@"value"];
+
+ XCTAssertFalse([selector acceptNode:_element]);
+
+ _element[@"class"] = @"class";
+ XCTAssertFalse([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"value";
+ XCTAssertTrue([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"a b value";
+ XCTAssertTrue([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"a value b";
+ XCTAssertTrue([selector acceptNode:_element]);
+
+ [_element.attributes removeObjectForKey:@"attr"];
+ XCTAssertFalse([selector acceptNode:_element]);
+}
+
+- (void)testAttributeBegins
+{
+ CSSAttributeSelector *selector = [[CSSAttributeSelector alloc] initWithType:CSSAttributeSelectorBegins
+ attributeName:@"attr"
+ attrbiuteValue:@"value"];
+
+ XCTAssertFalse([selector acceptNode:_element]);
+
+ _element[@"class"] = @"class";
+ XCTAssertFalse([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"val";
+ XCTAssertFalse([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"a value";
+ XCTAssertFalse([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"value";
+ XCTAssertTrue([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"values";
+ XCTAssertTrue([selector acceptNode:_element]);
+
+ [_element.attributes removeObjectForKey:@"attr"];
+ XCTAssertFalse([selector acceptNode:_element]);
+}
+
+- (void)testAttributeEnds
+{
+ CSSAttributeSelector *selector = [[CSSAttributeSelector alloc] initWithType:CSSAttributeSelectorEnds
+ attributeName:@"attr"
+ attrbiuteValue:@"value"];
+
+ XCTAssertFalse([selector acceptNode:_element]);
+
+ _element[@"class"] = @"class";
+ XCTAssertFalse([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"val";
+ XCTAssertFalse([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"value";
+ XCTAssertTrue([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"a value";
+ XCTAssertTrue([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"some-value";
+ XCTAssertTrue([selector acceptNode:_element]);
+
+ [_element.attributes removeObjectForKey:@"attr"];
+ XCTAssertFalse([selector acceptNode:_element]);
+}
+
+- (void)testAttributeContains
+{
+ CSSAttributeSelector *selector = [[CSSAttributeSelector alloc] initWithType:CSSAttributeSelectorContains
+ attributeName:@"attr"
+ attrbiuteValue:@"value"];
+
+ XCTAssertFalse([selector acceptNode:_element]);
+
+ _element[@"class"] = @"class";
+ XCTAssertFalse([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"val";
+ XCTAssertFalse([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"value";
+ XCTAssertTrue([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"a value b";
+ XCTAssertTrue([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"some-values";
+ XCTAssertTrue([selector acceptNode:_element]);
+
+ [_element.attributes removeObjectForKey:@"attr"];
+ XCTAssertFalse([selector acceptNode:_element]);
+}
+
+- (void)testAttributeHyphen
+{
+ CSSAttributeSelector *selector = [[CSSAttributeSelector alloc] initWithType:CSSAttributeSelectorHyphen
+ attributeName:@"attr"
+ attrbiuteValue:@"top"];
+
+ XCTAssertFalse([selector acceptNode:_element]);
+
+ _element[@"class"] = @"class";
+ XCTAssertFalse([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"top_text";
+ XCTAssertFalse([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"toptext";
+ XCTAssertFalse([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"top";
+ XCTAssertTrue([selector acceptNode:_element]);
+
+ _element[@"attr"] = @"top-text";
+ XCTAssertTrue([selector acceptNode:_element]);
+
+ [_element.attributes removeObjectForKey:@"attr"];
+ XCTAssertFalse([selector acceptNode:_element]);
+}
+
+@end
diff --git a/HTMLKitTests/CSSTypeSelectorTests.m b/HTMLKitTests/CSSTypeSelectorTests.m
new file mode 100644
index 0000000..88f13fd
--- /dev/null
+++ b/HTMLKitTests/CSSTypeSelectorTests.m
@@ -0,0 +1,51 @@
+//
+// CSSTypeSelectorTests.m
+// HTMLKit
+//
+// Created by Iska on 14/05/15.
+// Copyright (c) 2015 BrainCookie. All rights reserved.
+//
+
+#import
+#import "CSSSelectors.h"
+#import "HTMLNodes.h"
+
+@interface CSSTypeSelectorTests : XCTestCase
+
+@end
+
+@implementation CSSTypeSelectorTests
+
+- (void)testUniversalSelector
+{
+ CSSTypeSelector *selector = [CSSTypeSelector universalSelector];
+
+ XCTAssertFalse([selector acceptNode:[HTMLDocumentType new]]);
+ XCTAssertFalse([selector acceptNode:[HTMLDocumentFragment new]]);
+ XCTAssertFalse([selector acceptNode:[[HTMLText alloc] initWithData:@"Text"]]);
+ XCTAssertFalse([selector acceptNode:[[HTMLComment alloc] initWithData:@"Comment"]]);
+
+ XCTAssertTrue([selector acceptNode:[[HTMLElement alloc] initWithTagName:nil]]);
+ XCTAssertTrue([selector acceptNode:[[HTMLElement alloc] initWithTagName:@""]]);
+ XCTAssertTrue([selector acceptNode:[[HTMLElement alloc] initWithTagName:@"div"]]);
+ XCTAssertTrue([selector acceptNode:[[HTMLElement alloc] initWithTagName:@"p"]]);
+ XCTAssertTrue([selector acceptNode:[[HTMLElement alloc] initWithTagName:@"any other name"]]);
+}
+
+- (void)testTypeSelector
+{
+ CSSTypeSelector *selector = [[CSSTypeSelector alloc] initWithType:@"div"];
+
+ XCTAssertFalse([selector acceptNode:[HTMLDocumentType new]]);
+ XCTAssertFalse([selector acceptNode:[HTMLDocumentFragment new]]);
+ XCTAssertFalse([selector acceptNode:[[HTMLText alloc] initWithData:@"Text"]]);
+ XCTAssertFalse([selector acceptNode:[[HTMLComment alloc] initWithData:@"Comment"]]);
+ XCTAssertFalse([selector acceptNode:[[HTMLElement alloc] initWithTagName:nil]]);
+ XCTAssertFalse([selector acceptNode:[[HTMLElement alloc] initWithTagName:@""]]);
+ XCTAssertFalse([selector acceptNode:[[HTMLElement alloc] initWithTagName:@"p"]]);
+ XCTAssertFalse([selector acceptNode:[[HTMLElement alloc] initWithTagName:@"any other name"]]);
+
+ XCTAssertTrue([selector acceptNode:[[HTMLElement alloc] initWithTagName:@"div"]]);
+}
+
+@end