1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <stddef.h> 6#include <stdint.h> 7 8#include "mojo/public/interfaces/bindings/tests/test_structs.mojom.h" 9#include "testing/gtest/include/gtest/gtest.h" 10 11namespace mojo { 12namespace { 13 14struct RedmondRect { 15 int32_t left; 16 int32_t top; 17 int32_t right; 18 int32_t bottom; 19}; 20 21struct RedmondNamedRegion { 22 std::string name; 23 std::vector<RedmondRect> rects; 24}; 25 26bool AreEqualRectArrays(const Array<test::RectPtr>& rects1, 27 const Array<test::RectPtr>& rects2) { 28 if (rects1.size() != rects2.size()) 29 return false; 30 31 for (size_t i = 0; i < rects1.size(); ++i) { 32 if (rects1[i]->x != rects2[i]->x || rects1[i]->y != rects2[i]->y || 33 rects1[i]->width != rects2[i]->width || 34 rects1[i]->height != rects2[i]->height) { 35 return false; 36 } 37 } 38 39 return true; 40} 41 42} // namespace 43 44template <> 45struct TypeConverter<test::RectPtr, RedmondRect> { 46 static test::RectPtr Convert(const RedmondRect& input) { 47 test::RectPtr rect(test::Rect::New()); 48 rect->x = input.left; 49 rect->y = input.top; 50 rect->width = input.right - input.left; 51 rect->height = input.bottom - input.top; 52 return rect; 53 } 54}; 55 56template <> 57struct TypeConverter<RedmondRect, test::RectPtr> { 58 static RedmondRect Convert(const test::RectPtr& input) { 59 RedmondRect rect; 60 rect.left = input->x; 61 rect.top = input->y; 62 rect.right = input->x + input->width; 63 rect.bottom = input->y + input->height; 64 return rect; 65 } 66}; 67 68template <> 69struct TypeConverter<test::NamedRegionPtr, RedmondNamedRegion> { 70 static test::NamedRegionPtr Convert(const RedmondNamedRegion& input) { 71 test::NamedRegionPtr region(test::NamedRegion::New()); 72 region->name.emplace(input.name); 73 region->rects = Array<test::RectPtr>::From(input.rects).PassStorage(); 74 return region; 75 } 76}; 77 78template <> 79struct TypeConverter<RedmondNamedRegion, test::NamedRegionPtr> { 80 static RedmondNamedRegion Convert(const test::NamedRegionPtr& input) { 81 RedmondNamedRegion region; 82 if (input->name) 83 region.name = input->name.value(); 84 if (input->rects) { 85 region.rects.reserve(input->rects->size()); 86 for (const auto& element : *input->rects) 87 region.rects.push_back(element.To<RedmondRect>()); 88 } 89 return region; 90 } 91}; 92 93namespace test { 94namespace { 95 96TEST(TypeConversionTest, String) { 97 const char kText[6] = "hello"; 98 99 String a = std::string(kText); 100 String b(kText); 101 String c(static_cast<const char*>(kText)); 102 103 EXPECT_EQ(std::string(kText), a.To<std::string>()); 104 EXPECT_EQ(std::string(kText), b.To<std::string>()); 105 EXPECT_EQ(std::string(kText), c.To<std::string>()); 106} 107 108TEST(TypeConversionTest, String_Null) { 109 String a(nullptr); 110 EXPECT_TRUE(a.is_null()); 111 EXPECT_EQ(std::string(), a.To<std::string>()); 112 113 String b = String::From(static_cast<const char*>(nullptr)); 114 EXPECT_TRUE(b.is_null()); 115} 116 117TEST(TypeConversionTest, String_Empty) { 118 String a = ""; 119 EXPECT_EQ(std::string(), a.To<std::string>()); 120 121 String b = std::string(); 122 EXPECT_FALSE(b.is_null()); 123 EXPECT_EQ(std::string(), b.To<std::string>()); 124} 125 126TEST(TypeConversionTest, StringWithEmbeddedNull) { 127 const std::string kText("hel\0lo", 6); 128 129 String a(kText); 130 EXPECT_EQ(kText, a.To<std::string>()); 131 132 // Expect truncation: 133 String b(kText.c_str()); 134 EXPECT_EQ(std::string("hel"), b.To<std::string>()); 135} 136 137TEST(TypeConversionTest, CustomTypeConverter) { 138 RectPtr rect(Rect::New()); 139 rect->x = 10; 140 rect->y = 20; 141 rect->width = 50; 142 rect->height = 45; 143 144 RedmondRect rr = rect.To<RedmondRect>(); 145 EXPECT_EQ(10, rr.left); 146 EXPECT_EQ(20, rr.top); 147 EXPECT_EQ(60, rr.right); 148 EXPECT_EQ(65, rr.bottom); 149 150 RectPtr rect2(Rect::From(rr)); 151 EXPECT_EQ(rect->x, rect2->x); 152 EXPECT_EQ(rect->y, rect2->y); 153 EXPECT_EQ(rect->width, rect2->width); 154 EXPECT_EQ(rect->height, rect2->height); 155} 156 157TEST(TypeConversionTest, CustomTypeConverter_Array_Null) { 158 Array<RectPtr> rects; 159 160 std::vector<RedmondRect> redmond_rects = rects.To<std::vector<RedmondRect>>(); 161 162 EXPECT_TRUE(redmond_rects.empty()); 163} 164 165TEST(TypeConversionTest, CustomTypeConverter_Array) { 166 const RedmondRect kBase = {10, 20, 30, 40}; 167 168 Array<RectPtr> rects(10); 169 for (size_t i = 0; i < rects.size(); ++i) { 170 RedmondRect rr = kBase; 171 rr.left += static_cast<int32_t>(i); 172 rr.top += static_cast<int32_t>(i); 173 rects[i] = Rect::From(rr); 174 } 175 176 std::vector<RedmondRect> redmond_rects = rects.To<std::vector<RedmondRect>>(); 177 178 Array<RectPtr> rects2 = Array<RectPtr>::From(redmond_rects); 179 EXPECT_TRUE(AreEqualRectArrays(rects, rects2)); 180} 181 182TEST(TypeConversionTest, CustomTypeConverter_Nested) { 183 RedmondNamedRegion redmond_region; 184 redmond_region.name = "foopy"; 185 186 const RedmondRect kBase = {10, 20, 30, 40}; 187 188 for (size_t i = 0; i < 10; ++i) { 189 RedmondRect rect = kBase; 190 rect.left += static_cast<int32_t>(i); 191 rect.top += static_cast<int32_t>(i); 192 redmond_region.rects.push_back(rect); 193 } 194 195 // Round-trip through generated struct and TypeConverter. 196 197 NamedRegionPtr copy = NamedRegion::From(redmond_region); 198 RedmondNamedRegion redmond_region2 = copy.To<RedmondNamedRegion>(); 199 200 EXPECT_EQ(redmond_region.name, redmond_region2.name); 201 EXPECT_EQ(redmond_region.rects.size(), redmond_region2.rects.size()); 202 for (size_t i = 0; i < redmond_region.rects.size(); ++i) { 203 EXPECT_EQ(redmond_region.rects[i].left, redmond_region2.rects[i].left); 204 EXPECT_EQ(redmond_region.rects[i].top, redmond_region2.rects[i].top); 205 EXPECT_EQ(redmond_region.rects[i].right, redmond_region2.rects[i].right); 206 EXPECT_EQ(redmond_region.rects[i].bottom, redmond_region2.rects[i].bottom); 207 } 208} 209 210} // namespace 211} // namespace test 212} // namespace mojo 213