| //===- unittest/Format/ObjCPropertyAttributeOrderFixerTest.cpp - unit tests |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "../lib/Format/ObjCPropertyAttributeOrderFixer.h" |
| #include "FormatTestBase.h" |
| #include "TestLexer.h" |
| |
| #define DEBUG_TYPE "format-objc-property-attribute-order-fixer-test" |
| |
| namespace clang { |
| namespace format { |
| namespace test { |
| namespace { |
| |
| #define CHECK_PARSE(TEXT, FIELD, VALUE) \ |
| EXPECT_NE(VALUE, Style.FIELD) << "Initial value already the same!"; \ |
| EXPECT_EQ(0, parseConfiguration(TEXT, &Style).value()); \ |
| EXPECT_EQ(VALUE, Style.FIELD) << "Unexpected value after parsing!" |
| |
| #define FAIL_PARSE(TEXT, FIELD, VALUE) \ |
| EXPECT_NE(0, parseConfiguration(TEXT, &Style).value()); \ |
| EXPECT_EQ(VALUE, Style.FIELD) << "Unexpected value after parsing!" |
| |
| class ObjCPropertyAttributeOrderFixerTest : public FormatTestBase { |
| protected: |
| TokenList annotate(llvm::StringRef Code, |
| const FormatStyle &Style = getLLVMStyle()) { |
| return TestLexer(Allocator, Buffers, Style).annotate(Code); |
| } |
| |
| llvm::SpecificBumpPtrAllocator<FormatToken> Allocator; |
| std::vector<std::unique_ptr<llvm::MemoryBuffer>> Buffers; |
| }; |
| |
| TEST_F(ObjCPropertyAttributeOrderFixerTest, ParsesStyleOption) { |
| FormatStyle Style = {}; |
| Style.Language = FormatStyle::LK_ObjC; |
| |
| CHECK_PARSE("ObjCPropertyAttributeOrder: [class]", ObjCPropertyAttributeOrder, |
| std::vector<std::string>({"class"})); |
| |
| CHECK_PARSE("ObjCPropertyAttributeOrder: [" |
| "class, direct, atomic, nonatomic, " |
| "assign, retain, strong, copy, weak, unsafe_unretained, " |
| "readonly, readwrite, getter, setter, " |
| "nullable, nonnull, null_resettable, null_unspecified" |
| "]", |
| ObjCPropertyAttributeOrder, |
| std::vector<std::string>({ |
| "class", |
| "direct", |
| "atomic", |
| "nonatomic", |
| "assign", |
| "retain", |
| "strong", |
| "copy", |
| "weak", |
| "unsafe_unretained", |
| "readonly", |
| "readwrite", |
| "getter", |
| "setter", |
| "nullable", |
| "nonnull", |
| "null_resettable", |
| "null_unspecified", |
| })); |
| } |
| |
| TEST_F(ObjCPropertyAttributeOrderFixerTest, SortsSpecifiedAttributes) { |
| FormatStyle Style = getLLVMStyle(); |
| Style.Language = FormatStyle::LK_ObjC; |
| Style.ObjCPropertyAttributeOrder = {"a", "b", "c"}; |
| |
| // Zero: nothing to do, but is legal. |
| verifyFormat("@property() int p;", Style); |
| |
| // One: shouldn't move. |
| verifyFormat("@property(a) int p;", Style); |
| verifyFormat("@property(b) int p;", Style); |
| verifyFormat("@property(c) int p;", Style); |
| |
| // Two in correct order already: no change. |
| verifyFormat("@property(a, b) int p;", Style); |
| verifyFormat("@property(a, c) int p;", Style); |
| verifyFormat("@property(b, c) int p;", Style); |
| |
| // Three in correct order already: no change. |
| verifyFormat("@property(a, b, c) int p;", Style); |
| |
| // Two wrong order. |
| verifyFormat("@property(a, b) int p;", "@property(b, a) int p;", Style); |
| verifyFormat("@property(a, c) int p;", "@property(c, a) int p;", Style); |
| verifyFormat("@property(b, c) int p;", "@property(c, b) int p;", Style); |
| |
| // Three wrong order. |
| verifyFormat("@property(a, b, c) int p;", "@property(b, a, c) int p;", Style); |
| verifyFormat("@property(a, b, c) int p;", "@property(c, b, a) int p;", Style); |
| |
| // Check that properties preceded by @optional/@required work. |
| verifyFormat("@optional\n" |
| "@property(a, b) int p;", |
| "@optional @property(b, a) int p;", Style); |
| verifyFormat("@required\n" |
| "@property(a, b) int p;", |
| "@required @property(b, a) int p;", Style); |
| |
| // Check two `@property`s on one-line are reflowed (by other passes) |
| // and both have their attributes reordered. |
| verifyFormat("@property(a, b) int p;\n" |
| "@property(a, b) int q;", |
| "@property(b, a) int p; @property(b, a) int q;", Style); |
| } |
| |
| TEST_F(ObjCPropertyAttributeOrderFixerTest, SortsAttributesWithValues) { |
| FormatStyle Style = getLLVMStyle(); |
| Style.Language = FormatStyle::LK_ObjC; |
| Style.ObjCPropertyAttributeOrder = {"a", "getter", "c"}; |
| |
| // No change |
| verifyFormat("@property(getter=G, c) int p;", Style); |
| verifyFormat("@property(a, getter=G) int p;", Style); |
| verifyFormat("@property(a, getter=G, c) int p;", Style); |
| |
| // Reorder |
| verifyFormat("@property(getter=G, c) int p;", "@property(c, getter=G) int p;", |
| Style); |
| verifyFormat("@property(a, getter=G) int p;", "@property(getter=G, a) int p;", |
| Style); |
| verifyFormat("@property(a, getter=G, c) int p;", |
| "@property(getter=G, c, a) int p;", Style); |
| |
| // Multiple set properties, including ones not recognized |
| verifyFormat("@property(a=A, c=C, x=X, y=Y) int p;", |
| "@property(c=C, x=X, y=Y, a=A) int p;", Style); |
| } |
| |
| TEST_F(ObjCPropertyAttributeOrderFixerTest, SortsUnspecifiedAttributesToBack) { |
| FormatStyle Style = getLLVMStyle(); |
| Style.Language = FormatStyle::LK_ObjC; |
| Style.ObjCPropertyAttributeOrder = {"a", "b", "c"}; |
| |
| verifyFormat("@property(x) int p;", Style); |
| |
| // No change in order. |
| verifyFormat("@property(a, x, y) int p;", Style); |
| verifyFormat("@property(b, x, y) int p;", Style); |
| verifyFormat("@property(a, b, c, x, y) int p;", Style); |
| |
| // Reorder one unrecognized one. |
| verifyFormat("@property(a, x) int p;", "@property(x, a) int p;", Style); |
| |
| // Prove the unrecognized ones have a stable sort order |
| verifyFormat("@property(a, b, x, y) int p;", "@property(x, b, y, a) int p;", |
| Style); |
| verifyFormat("@property(a, b, y, x) int p;", "@property(y, b, x, a) int p;", |
| Style); |
| } |
| |
| TEST_F(ObjCPropertyAttributeOrderFixerTest, HandlesDuplicatedAttributes) { |
| // Duplicated attributes aren't rejected by the compiler even if it's silly |
| // to do so. Preserve them and sort them best-effort. |
| FormatStyle Style = getLLVMStyle(); |
| Style.Language = FormatStyle::LK_ObjC; |
| Style.ObjCPropertyAttributeOrder = {"a", "b", "c"}; |
| |
| // Just a dup and nothing else. |
| verifyFormat("@property(a) int p;", "@property(a, a) int p;", Style); |
| |
| // A dup and something else. |
| verifyFormat("@property(a, b) int p;", "@property(a, b, a) int p;", Style); |
| |
| // Duplicates using `=`. |
| verifyFormat("@property(a=A, b=X) int p;", |
| "@property(a=A, b=X, a=A, b=Y) int p;", Style); |
| verifyFormat("@property(a=A, b=Y) int p;", |
| "@property(a=A, b=Y, a=A, b=X) int p;", Style); |
| verifyFormat("@property(a, b=B) int p;", "@property(a, b=B, a=A, b) int p;", |
| Style); |
| } |
| |
| TEST_F(ObjCPropertyAttributeOrderFixerTest, SortsInPPDirective) { |
| FormatStyle Style = getLLVMStyle(); |
| Style.Language = FormatStyle::LK_ObjC; |
| Style.ObjCPropertyAttributeOrder = {"a", "b", "c"}; |
| |
| // Spot-check a few simple cases that require sorting in a macro definition. |
| verifyFormat("#define MACRO @property() int p;", Style); |
| verifyFormat("#define MACRO @property(a) int p;", Style); |
| verifyFormat("#define MACRO @property(a, b) int p;", |
| "#define MACRO @property(b, a) int p;", Style); |
| verifyFormat("#define MACRO @property(a, b, c) int p;", |
| "#define MACRO @property(c, b, a) int p;", Style); |
| } |
| |
| TEST_F(ObjCPropertyAttributeOrderFixerTest, HandlesAllAttributes) { |
| // `class` is the only attribute that is a keyword, so make sure it works too. |
| FormatStyle Style = getLLVMStyle(); |
| Style.Language = FormatStyle::LK_ObjC; |
| Style.ObjCPropertyAttributeOrder = {"FIRST", |
| "class", |
| "direct", |
| "atomic", |
| "nonatomic", |
| "assign", |
| "retain", |
| "strong", |
| "copy", |
| "weak", |
| "unsafe_unretained", |
| "readonly", |
| "readwrite", |
| "getter", |
| "setter", |
| "nullable", |
| "nonnull", |
| "null_resettable", |
| "null_unspecified", |
| "LAST"}; |
| |
| // No change: specify all attributes in the correct order. |
| verifyFormat("@property(class, LAST) int p;", Style); |
| verifyFormat("@property(direct, LAST) int p;", Style); |
| verifyFormat("@property(atomic, LAST) int p;", Style); |
| verifyFormat("@property(nonatomic, LAST) int p;", Style); |
| verifyFormat("@property(assign, LAST) int p;", Style); |
| verifyFormat("@property(retain, LAST) int p;", Style); |
| verifyFormat("@property(strong, LAST) int p;", Style); |
| verifyFormat("@property(copy, LAST) int p;", Style); |
| verifyFormat("@property(weak, LAST) int p;", Style); |
| verifyFormat("@property(unsafe_unretained, LAST) int p;", Style); |
| verifyFormat("@property(readonly, LAST) int p;", Style); |
| verifyFormat("@property(readwrite, LAST) int p;", Style); |
| verifyFormat("@property(getter, LAST) int p;", Style); |
| verifyFormat("@property(setter, LAST) int p;", Style); |
| verifyFormat("@property(nullable, LAST) int p;", Style); |
| verifyFormat("@property(nonnull, LAST) int p;", Style); |
| verifyFormat("@property(null_resettable, LAST) int p;", Style); |
| verifyFormat("@property(null_unspecified, LAST) int p;", Style); |
| |
| verifyFormat("@property(FIRST, class) int p;", Style); |
| verifyFormat("@property(FIRST, direct) int p;", Style); |
| verifyFormat("@property(FIRST, atomic) int p;", Style); |
| verifyFormat("@property(FIRST, nonatomic) int p;", Style); |
| verifyFormat("@property(FIRST, assign) int p;", Style); |
| verifyFormat("@property(FIRST, retain) int p;", Style); |
| verifyFormat("@property(FIRST, strong) int p;", Style); |
| verifyFormat("@property(FIRST, copy) int p;", Style); |
| verifyFormat("@property(FIRST, weak) int p;", Style); |
| verifyFormat("@property(FIRST, unsafe_unretained) int p;", Style); |
| verifyFormat("@property(FIRST, readonly) int p;", Style); |
| verifyFormat("@property(FIRST, readwrite) int p;", Style); |
| verifyFormat("@property(FIRST, getter) int p;", Style); |
| verifyFormat("@property(FIRST, setter) int p;", Style); |
| verifyFormat("@property(FIRST, nullable) int p;", Style); |
| verifyFormat("@property(FIRST, nonnull) int p;", Style); |
| verifyFormat("@property(FIRST, null_resettable) int p;", Style); |
| verifyFormat("@property(FIRST, null_unspecified) int p;", Style); |
| |
| verifyFormat("@property(FIRST, class, LAST) int p;", Style); |
| verifyFormat("@property(FIRST, direct, LAST) int p;", Style); |
| verifyFormat("@property(FIRST, atomic, LAST) int p;", Style); |
| verifyFormat("@property(FIRST, nonatomic, LAST) int p;", Style); |
| verifyFormat("@property(FIRST, assign, LAST) int p;", Style); |
| verifyFormat("@property(FIRST, retain, LAST) int p;", Style); |
| verifyFormat("@property(FIRST, strong, LAST) int p;", Style); |
| verifyFormat("@property(FIRST, copy, LAST) int p;", Style); |
| verifyFormat("@property(FIRST, weak, LAST) int p;", Style); |
| verifyFormat("@property(FIRST, unsafe_unretained, LAST) int p;", Style); |
| verifyFormat("@property(FIRST, readonly, LAST) int p;", Style); |
| verifyFormat("@property(FIRST, readwrite, LAST) int p;", Style); |
| verifyFormat("@property(FIRST, getter, LAST) int p;", Style); |
| verifyFormat("@property(FIRST, setter, LAST) int p;", Style); |
| verifyFormat("@property(FIRST, nullable, LAST) int p;", Style); |
| verifyFormat("@property(FIRST, nonnull, LAST) int p;", Style); |
| verifyFormat("@property(FIRST, null_resettable, LAST) int p;", Style); |
| verifyFormat("@property(FIRST, null_unspecified, LAST) int p;", Style); |
| |
| // Reorder: put `FIRST` and/or `LAST` in the wrong spot. |
| verifyFormat("@property(class, LAST) int p;", "@property(LAST, class) int p;", |
| Style); |
| verifyFormat("@property(direct, LAST) int p;", |
| "@property(LAST, direct) int p;", Style); |
| verifyFormat("@property(atomic, LAST) int p;", |
| "@property(LAST, atomic) int p;", Style); |
| verifyFormat("@property(nonatomic, LAST) int p;", |
| "@property(LAST, nonatomic) int p;", Style); |
| verifyFormat("@property(assign, LAST) int p;", |
| "@property(LAST, assign) int p;", Style); |
| verifyFormat("@property(retain, LAST) int p;", |
| "@property(LAST, retain) int p;", Style); |
| verifyFormat("@property(strong, LAST) int p;", |
| "@property(LAST, strong) int p;", Style); |
| verifyFormat("@property(copy, LAST) int p;", "@property(LAST, copy) int p;", |
| Style); |
| verifyFormat("@property(weak, LAST) int p;", "@property(LAST, weak) int p;", |
| Style); |
| verifyFormat("@property(unsafe_unretained, LAST) int p;", |
| "@property(LAST, unsafe_unretained) int p;", Style); |
| verifyFormat("@property(readonly, LAST) int p;", |
| "@property(LAST, readonly) int p;", Style); |
| verifyFormat("@property(readwrite, LAST) int p;", |
| "@property(LAST, readwrite) int p;", Style); |
| verifyFormat("@property(getter, LAST) int p;", |
| "@property(LAST, getter) int p;", Style); |
| verifyFormat("@property(setter, LAST) int p;", |
| "@property(LAST, setter) int p;", Style); |
| verifyFormat("@property(nullable, LAST) int p;", |
| "@property(LAST, nullable) int p;", Style); |
| verifyFormat("@property(nonnull, LAST) int p;", |
| "@property(LAST, nonnull) int p;", Style); |
| verifyFormat("@property(null_resettable, LAST) int p;", |
| "@property(LAST, null_resettable) int p;", Style); |
| verifyFormat("@property(null_unspecified, LAST) int p;", |
| "@property(LAST, null_unspecified) int p;", Style); |
| |
| verifyFormat("@property(FIRST, class) int p;", |
| "@property(class, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, direct) int p;", |
| "@property(direct, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, atomic) int p;", |
| "@property(atomic, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, nonatomic) int p;", |
| "@property(nonatomic, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, assign) int p;", |
| "@property(assign, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, retain) int p;", |
| "@property(retain, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, strong) int p;", |
| "@property(strong, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, copy) int p;", "@property(copy, FIRST) int p;", |
| Style); |
| verifyFormat("@property(FIRST, weak) int p;", "@property(weak, FIRST) int p;", |
| Style); |
| verifyFormat("@property(FIRST, unsafe_unretained) int p;", |
| "@property(unsafe_unretained, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, readonly) int p;", |
| "@property(readonly, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, readwrite) int p;", |
| "@property(readwrite, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, getter) int p;", |
| "@property(getter, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, setter) int p;", |
| "@property(setter, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, nullable) int p;", |
| "@property(nullable, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, nonnull) int p;", |
| "@property(nonnull, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, null_resettable) int p;", |
| "@property(null_resettable, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, null_unspecified) int p;", |
| "@property(null_unspecified, FIRST) int p;", Style); |
| |
| verifyFormat("@property(FIRST, class, LAST) int p;", |
| "@property(LAST, class, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, direct, LAST) int p;", |
| "@property(LAST, direct, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, atomic, LAST) int p;", |
| "@property(LAST, atomic, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, nonatomic, LAST) int p;", |
| "@property(LAST, nonatomic, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, assign, LAST) int p;", |
| "@property(LAST, assign, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, retain, LAST) int p;", |
| "@property(LAST, retain, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, strong, LAST) int p;", |
| "@property(LAST, strong, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, copy, LAST) int p;", |
| "@property(LAST, copy, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, weak, LAST) int p;", |
| "@property(LAST, weak, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, unsafe_unretained, LAST) int p;", |
| "@property(LAST, unsafe_unretained, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, readonly, LAST) int p;", |
| "@property(LAST, readonly, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, readwrite, LAST) int p;", |
| "@property(LAST, readwrite, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, getter, LAST) int p;", |
| "@property(LAST, getter, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, setter, LAST) int p;", |
| "@property(LAST, setter, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, nullable, LAST) int p;", |
| "@property(LAST, nullable, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, nonnull, LAST) int p;", |
| "@property(LAST, nonnull, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, null_resettable, LAST) int p;", |
| "@property(LAST, null_resettable, FIRST) int p;", Style); |
| verifyFormat("@property(FIRST, null_unspecified, LAST) int p;", |
| "@property(LAST, null_unspecified, FIRST) int p;", Style); |
| } |
| |
| TEST_F(ObjCPropertyAttributeOrderFixerTest, HandlesCommentsAroundAttributes) { |
| FormatStyle Style = getLLVMStyle(); |
| Style.Language = FormatStyle::LK_ObjC; |
| Style.ObjCPropertyAttributeOrder = {"a", "b"}; |
| |
| // Zero attributes but comments. |
| verifyFormat("@property(/* 1 */) int p;", Style); |
| verifyFormat("@property(/* 1 */ /* 2 */) int p;", Style); |
| |
| // One attribute with comments before or after. |
| verifyFormat("@property(/* 1 */ a) int p;", Style); |
| verifyFormat("@property(a /* 2 */) int p;", Style); |
| verifyFormat("@property(/* 1 */ a /* 2 */) int p;", Style); |
| |
| // No reordering if comments are encountered anywhere. |
| // (Each case represents a reordering that would have happened |
| // without the comment.) |
| verifyFormat("@property(/* before */ b, a) int p;", Style); |
| verifyFormat("@property(b, /* between */ a) int p;", Style); |
| verifyFormat("@property(b, a /* after */) int p;", Style); |
| } |
| |
| } // namespace |
| } // namespace test |
| } // namespace format |
| } // namespace clang |