Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(273)

Unified Diff: ios/net/clients/crn_forwarding_network_client_factory_unittest.mm

Issue 994823004: [iOS] Upstream //ios/net (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ios/net/clients/crn_forwarding_network_client_factory_unittest.mm
diff --git a/ios/net/clients/crn_forwarding_network_client_factory_unittest.mm b/ios/net/clients/crn_forwarding_network_client_factory_unittest.mm
new file mode 100644
index 0000000000000000000000000000000000000000..735c7f512aeb104256d650ac4ea84edcd38ed098
--- /dev/null
+++ b/ios/net/clients/crn_forwarding_network_client_factory_unittest.mm
@@ -0,0 +1,220 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Foundation/Foundation.h>
+#import <objc/runtime.h>
+
+#include "base/mac/scoped_nsobject.h"
+#include "base/strings/string_util.h"
+#include "base/strings/sys_string_conversions.h"
+#import "ios/net/clients/crn_forwarding_network_client_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+@interface TestFactoryA : CRNForwardingNetworkClientFactory
+@end
+@implementation TestFactoryA
+@end
+
+// B must appear before A
+@interface TestFactoryB : CRNForwardingNetworkClientFactory
+@end
+@implementation TestFactoryB
++ (instancetype)mustApplyBefore { return [TestFactoryA class]; }
+@end
+
+// C must appear after A
+@interface TestFactoryC : CRNForwardingNetworkClientFactory
+@end
+@implementation TestFactoryC
++ (instancetype)mustApplyAfter { return [TestFactoryA class]; }
+@end
+
+// D must appear after B and before C
+@interface TestFactoryD : CRNForwardingNetworkClientFactory
+@end
+@implementation TestFactoryD
++ (instancetype)mustApplyAfter { return [TestFactoryB class]; }
++ (instancetype)mustApplyBefore { return [TestFactoryC class]; }
+@end
+
+// E and F form a loop
+@interface TestFactoryE : CRNForwardingNetworkClientFactory
+@end
+@interface TestFactoryF : CRNForwardingNetworkClientFactory
+@end
+@implementation TestFactoryE
++ (instancetype)mustApplyAfter { return [TestFactoryF class]; }
+@end
+@implementation TestFactoryF
++ (instancetype)mustApplyAfter { return [TestFactoryE class]; }
+@end
+
+// G must appear before B and after C, so while not a loop, it can't be
+// ordered consistently.
+@interface TestFactoryG : CRNForwardingNetworkClientFactory
+@end
+@implementation TestFactoryG
++ (instancetype)mustApplyAfter { return [TestFactoryC class]; }
++ (instancetype)mustApplyBefore { return [TestFactoryB class]; }
+@end
+
+namespace {
+
+class ForwardingNetworkClientFactoryTest : public testing::Test {
+ public:
+ ForwardingNetworkClientFactoryTest() {}
+
+ void SetUp() override {
+ factory_a_.reset([[TestFactoryA alloc] init]);
+ factory_b_.reset([[TestFactoryB alloc] init]);
+ factory_c_.reset([[TestFactoryC alloc] init]);
+ factory_d_.reset([[TestFactoryD alloc] init]);
+ }
+
+ protected:
+ base::scoped_nsobject<TestFactoryA> factory_a_;
+ base::scoped_nsobject<TestFactoryB> factory_b_;
+ base::scoped_nsobject<TestFactoryC> factory_c_;
+ base::scoped_nsobject<TestFactoryD> factory_d_;
+};
+
+} // namespace
+
+TEST_F(ForwardingNetworkClientFactoryTest, SortFactories) {
+ base::scoped_nsobject<NSMutableArray> array([[NSMutableArray alloc] init]);
+
+ // Add a, c, b.
+ EXPECT_TRUE([[TestFactoryA class] orderedOK]);
+ EXPECT_TRUE([[TestFactoryB class] orderedOK]);
+ EXPECT_TRUE([[TestFactoryC class] orderedOK]);
+ [array addObject:factory_a_.get()];
+ [array addObject:factory_b_.get()];
+ [array addObject:factory_c_.get()];
+ [array sortUsingSelector:@selector(orderRelativeTo:)];
+ // Expect b before a.
+ EXPECT_LT([array indexOfObject:factory_b_.get()],
+ [array indexOfObject:factory_a_.get()]);
+ // Expect c after a.
+ EXPECT_GT([array indexOfObject:factory_c_.get()],
+ [array indexOfObject:factory_a_.get()]);
+
+ // Add d.
+ EXPECT_TRUE([[TestFactoryD class] orderedOK]);
+ [array addObject:factory_d_.get()];
+ [array sortUsingSelector:@selector(orderRelativeTo:)];
+ // Expect previous relations unchanged.
+ EXPECT_LT([array indexOfObject:factory_b_.get()],
+ [array indexOfObject:factory_a_.get()]);
+ EXPECT_GT([array indexOfObject:factory_c_.get()],
+ [array indexOfObject:factory_a_.get()]);
+ // Expect b before d.
+ EXPECT_LT([array indexOfObject:factory_b_.get()],
+ [array indexOfObject:factory_d_.get()]);
+ // Expect c after d.
+ EXPECT_GT([array indexOfObject:factory_c_.get()],
+ [array indexOfObject:factory_d_.get()]);
+
+ // E and F are not OK.
+ EXPECT_FALSE([[TestFactoryE class] orderedOK]);
+ EXPECT_FALSE([[TestFactoryF class] orderedOK]);
+
+ // G is not OK.
+ EXPECT_FALSE([[TestFactoryG class] orderedOK]);
+}
+
+TEST_F(ForwardingNetworkClientFactoryTest, TestSubclassImplementations) {
+ // Look at all the subclasses of of CRNForwardingNetworkClientFactory.
+ // Make sure that each one implements at least one clientHandling.. method.
+ Class factory_superclass = [CRNForwardingNetworkClientFactory class];
+ std::string superclass_name = class_getName(factory_superclass);
+
+ base::scoped_nsobject<NSMutableArray> subclasses(
+ [[NSMutableArray alloc] init]);
+
+ // Look at every known class and find those that are subclasses of
+ // |factory_superclass|.
+ int class_count = objc_getClassList(nullptr, 0);
+ Class* classes = nullptr;
+ classes = static_cast<Class*>(malloc(sizeof(Class) * class_count));
+ class_count = objc_getClassList(classes, class_count);
+
+ for (NSInteger i = 0; i < class_count; i++) {
+ std::string class_name = class_getName(classes[i]);
+ // Skip the test classes defined above.
+ if (StartsWithASCII(class_name, "TestFactory", false))
+ continue;
+
+ Class subclass_super = classes[i];
+ int subclassing_count = 0;
+ // Walk up the class hiererchy from |classes[i]| to |factory_superclass|.
+ do {
+ subclass_super = class_getSuperclass(subclass_super);
+ subclassing_count++;
+ } while (subclass_super && subclass_super != factory_superclass);
+
+ if (subclass_super == nil)
+ continue;
+
+ // If |subclassing_count| > 1 we have found a class that is a subclass of
+ // a subclass of |factory_superclass|, which we want to (for now) flag.
+ EXPECT_EQ(1, subclassing_count)
+ << class_name << " is an indirect subclass of " << superclass_name;
+
+ [subclasses addObject:classes[i]];
+ }
+
+ // Get all of the methods defined in ForwardingNetworkClientFactoryTest and
+ // compile a list of those named "clientHandling...".
+ base::scoped_nsobject<NSMutableArray> client_handling_methods(
+ [[NSMutableArray alloc] init]);
+ unsigned int method_count;
+ Method* superclass_methods =
+ class_copyMethodList(factory_superclass, &method_count);
+ for (unsigned int i = 0; i < method_count; i++) {
+ NSString* method_name =
+ NSStringFromSelector(method_getName(superclass_methods[i]));
+ if ([method_name hasPrefix:@"clientHandling"]) {
+ [client_handling_methods addObject:method_name];
+ }
+ }
+ free(superclass_methods);
+
+ // The superclass should implement at least one method.
+ EXPECT_LT(0u, [client_handling_methods count]);
+
+ for (Class subclass in subclasses.get()) {
+ Method* methods = class_copyMethodList(subclass, &method_count);
+ // The subclass has to have > 0 methods
+ EXPECT_LT(0u, method_count);
+
+ // Collect an array of the methods the class implements, then check each
+ // superclass clientHandling method to see if it's in the list.
+ base::scoped_nsobject<NSMutableArray> method_names(
+ [[NSMutableArray alloc] init]);
+ for (unsigned int i = 0; i < method_count; i++) {
+ [method_names addObject:NSStringFromSelector(method_getName(methods[i]))];
+ }
+ free(methods);
+
+ base::scoped_nsobject<NSMutableArray> subclass_implementations(
+ [[NSMutableArray alloc] init]);
+ for (NSString* superclass_method_name in client_handling_methods.get()) {
+ if ([method_names indexOfObject:superclass_method_name] != NSNotFound) {
+ [subclass_implementations addObject:superclass_method_name];
+ }
+ }
+
+ std::string class_name = class_getName(subclass);
+ std::string method_list = base::SysNSStringToUTF8(
+ [subclass_implementations componentsJoinedByString:@", "]);
+ ASSERT_NE(0u, [subclass_implementations count])
+ << class_name
+ << " does not implement any required clientHandling methods.";
+ ASSERT_EQ(1u, [subclass_implementations count])
+ << class_name << " implements too many superclass methods ("
+ << method_list << ").";
+ }
+
+ free(classes);
+}

Powered by Google App Engine
This is Rietveld 408576698