chromium/content/common/mac/attributed_string_type_converters_unittest.mm

// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "content/common/mac/attributed_string_type_converters.h"

#include <AppKit/AppKit.h>

#include <memory>

#include "base/apple/bridging.h"
#include "base/apple/foundation_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gtest_mac.h"

class AttributedStringConverterTest : public testing::Test {
 public:
  NSMutableAttributedString* AttributedString() {
    NSString* str = @"The quick brown fox jumped over the lazy dog.";
    return [[NSMutableAttributedString alloc] initWithString:str];
  }

  NSDictionary* FontAttributeDictionary(NSString* name, CGFloat size) {
    NSFont* font = [NSFont fontWithName:name size:size];
    return @{NSFontAttributeName : font};
  }

  NSAttributedString* ConvertAndRestore(NSAttributedString* str) {
    ui::mojom::AttributedStringPtr attributed_str =
        ui::mojom::AttributedString::From(base::apple::NSToCFPtrCast(str));
    return base::apple::CFToNSPtrCast(
        attributed_str.To<CFAttributedStringRef>());
  }
};

TEST_F(AttributedStringConverterTest, SimpleString) {
  NSMutableAttributedString* attr_str = AttributedString();
  [attr_str addAttributes:FontAttributeDictionary(@"Helvetica", 12.5)
                    range:NSMakeRange(0, attr_str.length)];

  NSAttributedString* ns_attributed_string = ConvertAndRestore(attr_str);
  EXPECT_NSEQ(attr_str, ns_attributed_string);
}

TEST_F(AttributedStringConverterTest, NoAttributes) {
  NSMutableAttributedString* attr_str = AttributedString();
  NSAttributedString* ns_attributed_string = ConvertAndRestore(attr_str);
  EXPECT_NSEQ(attr_str, ns_attributed_string);
}

TEST_F(AttributedStringConverterTest, StripColor) {
  NSMutableAttributedString* attr_str = AttributedString();
  const NSUInteger kStringLength = attr_str.length;
  [attr_str addAttribute:NSFontAttributeName
                   value:[NSFont systemFontOfSize:26]
                   range:NSMakeRange(0, kStringLength)];
  [attr_str addAttribute:NSForegroundColorAttributeName
                   value:NSColor.redColor
                   range:NSMakeRange(0, kStringLength)];

  NSAttributedString* ns_attributed_string = ConvertAndRestore(attr_str);

  NSRange range;
  NSDictionary* attrs = [ns_attributed_string attributesAtIndex:0
                                                 effectiveRange:&range];
  EXPECT_TRUE(NSEqualRanges(NSMakeRange(0, kStringLength), range));
  EXPECT_NSEQ([NSFont systemFontOfSize:26], attrs[NSFontAttributeName]);
  EXPECT_FALSE(attrs[NSForegroundColorAttributeName]);
}

TEST_F(AttributedStringConverterTest, MultipleFonts) {
  NSMutableAttributedString* attr_str = AttributedString();
  [attr_str setAttributes:FontAttributeDictionary(@"Courier", 12)
                    range:NSMakeRange(0, 10)];
  [attr_str addAttributes:FontAttributeDictionary(@"Helvetica", 16)
                    range:NSMakeRange(12, 6)];
  [attr_str addAttributes:FontAttributeDictionary(@"Helvetica", 14)
                    range:NSMakeRange(15, 5)];

  NSAttributedString* ns_attributed_string = ConvertAndRestore(attr_str);

  EXPECT_NSEQ(attr_str, ns_attributed_string);
}

TEST_F(AttributedStringConverterTest, NoPertinentAttributes) {
  NSMutableAttributedString* attr_str = AttributedString();
  [attr_str addAttribute:NSForegroundColorAttributeName
                   value:NSColor.blueColor
                   range:NSMakeRange(0, 10)];
  [attr_str addAttribute:NSBackgroundColorAttributeName
                   value:NSColor.blueColor
                   range:NSMakeRange(15, 5)];
  [attr_str addAttribute:NSKernAttributeName
                   value:@(2.6)
                   range:NSMakeRange(11, 3)];

  NSAttributedString* ns_attributed_string = ConvertAndRestore(attr_str);

  NSMutableAttributedString* expected = AttributedString();
  EXPECT_NSEQ(expected, ns_attributed_string);
}

TEST_F(AttributedStringConverterTest, NilString) {
  NSAttributedString* ns_attributed_string = ConvertAndRestore(nil);
  EXPECT_TRUE(ns_attributed_string);
  EXPECT_EQ(0U, ns_attributed_string.length);
}

TEST_F(AttributedStringConverterTest, OutOfRange) {
  NSFont* system_font = [NSFont systemFontOfSize:10];
  std::u16string font_name = base::SysNSStringToUTF16(system_font.fontName);
  ui::mojom::AttributedStringPtr attributed_string =
      ui::mojom::AttributedString::New();
  attributed_string->string = u"Hello World";
  attributed_string->attributes.push_back(
      ui::mojom::FontAttribute::New(font_name, 12, gfx::Range(0, 5)));
  attributed_string->attributes.push_back(
      ui::mojom::FontAttribute::New(font_name, 14, gfx::Range(5, 100)));
  attributed_string->attributes.push_back(
      ui::mojom::FontAttribute::New(font_name, 16, gfx::Range(100, 5)));

  CFAttributedStringRef cf_attributed_string =
      attributed_string.To<CFAttributedStringRef>();
  EXPECT_TRUE(cf_attributed_string);
  NSAttributedString* ns_attributed_string =
      base::apple::CFToNSPtrCast(cf_attributed_string);

  NSRange range;
  NSDictionary* attrs = [ns_attributed_string attributesAtIndex:0
                                                 effectiveRange:&range];
  EXPECT_NSEQ([NSFont systemFontOfSize:12], attrs[NSFontAttributeName]);
  EXPECT_TRUE(NSEqualRanges(range, NSMakeRange(0, 5)));

  attrs = [ns_attributed_string attributesAtIndex:5 effectiveRange:&range];
  EXPECT_FALSE(attrs[NSFontAttributeName]);
  EXPECT_EQ(0U, attrs.count);
}

TEST_F(AttributedStringConverterTest, SystemFontSubstitution) {
  // Ask for a specialization of the system font that the OS will refuse to
  // instantiate via the normal font APIs.
  std::u16string font_name = u".SFNS-Regular_wdth_opsz200000_GRAD_wght2BC0000";
  ui::mojom::AttributedStringPtr attributed_string =
      ui::mojom::AttributedString::New();
  attributed_string->string = u"Hello";
  attributed_string->attributes.push_back(
      ui::mojom::FontAttribute::New(font_name, 12, gfx::Range(0, 5)));

  CFAttributedStringRef cf_attributed_string =
      attributed_string.To<CFAttributedStringRef>();
  EXPECT_TRUE(cf_attributed_string);
  NSAttributedString* ns_attributed_string =
      base::apple::CFToNSPtrCast(cf_attributed_string);

  NSRange range;
  NSDictionary* attrs = [ns_attributed_string attributesAtIndex:0
                                                 effectiveRange:&range];
  EXPECT_NSEQ([NSFont systemFontOfSize:12], attrs[NSFontAttributeName]);
  EXPECT_TRUE(NSEqualRanges(range, NSMakeRange(0, 5)));
}