Skip to content

Commit ca356eb

Browse files
Halfdarkangelapolukhinhalfdarkangel
authored andcommitted
feat chaotic: escape emoji as 'U' and code point
Tests: протестировано CI --- Pull Request resolved: #1181 Co-authored-by: antoshkka <antoshkka@userver.tech> Co-authored-by: antoshkka <antoshkka@userver.tech> Co-authored-by: antoshkka <antoshkka@userver.tech> Co-authored-by: antoshkka <antoshkka@userver.tech> Co-authored-by: halfdarkangel <userty10012@gmail.com> commit_hash:0f7bf45d8652d824ab3680e52c4fc668d2121324
1 parent c6839fe commit ca356eb

6 files changed

Lines changed: 222 additions & 0 deletions

File tree

.mapping.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@
319319
"chaotic/integration_tests/schemas/container_format.yaml":"taxi/uservices/userver/chaotic/integration_tests/schemas/container_format.yaml",
320320
"chaotic/integration_tests/schemas/custom_cpp_type.yaml":"taxi/uservices/userver/chaotic/integration_tests/schemas/custom_cpp_type.yaml",
321321
"chaotic/integration_tests/schemas/date.yaml":"taxi/uservices/userver/chaotic/integration_tests/schemas/date.yaml",
322+
"chaotic/integration_tests/schemas/emoji_enum.yaml":"taxi/uservices/userver/chaotic/integration_tests/schemas/emoji_enum.yaml",
322323
"chaotic/integration_tests/schemas/external_ref.yaml":"taxi/uservices/userver/chaotic/integration_tests/schemas/external_ref.yaml",
323324
"chaotic/integration_tests/schemas/extra_container.yaml":"taxi/uservices/userver/chaotic/integration_tests/schemas/extra_container.yaml",
324325
"chaotic/integration_tests/schemas/indirect.yaml":"taxi/uservices/userver/chaotic/integration_tests/schemas/indirect.yaml",
@@ -347,6 +348,7 @@
347348
"chaotic/integration_tests/tests/my/custom_object.cpp":"taxi/uservices/userver/chaotic/integration_tests/tests/my/custom_object.cpp",
348349
"chaotic/integration_tests/tests/my/custom_one_of_with_discriminator.cpp":"taxi/uservices/userver/chaotic/integration_tests/tests/my/custom_one_of_with_discriminator.cpp",
349350
"chaotic/integration_tests/tests/render/custom.cpp":"taxi/uservices/userver/chaotic/integration_tests/tests/render/custom.cpp",
351+
"chaotic/integration_tests/tests/render/emoji_enum.cpp":"taxi/uservices/userver/chaotic/integration_tests/tests/render/emoji_enum.cpp",
350352
"chaotic/integration_tests/tests/render/formatter.cpp":"taxi/uservices/userver/chaotic/integration_tests/tests/render/formatter.cpp",
351353
"chaotic/integration_tests/tests/render/fwd.cpp":"taxi/uservices/userver/chaotic/integration_tests/tests/render/fwd.cpp",
352354
"chaotic/integration_tests/tests/render/logging.cpp":"taxi/uservices/userver/chaotic/integration_tests/tests/render/logging.cpp",

chaotic/chaotic/back/cpp/translator.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,13 +484,38 @@ def _gen_string(
484484
default=schema.default,
485485
)
486486

487+
@staticmethod
488+
def _is_emoji(code_point: int) -> bool:
489+
return (
490+
# Box Drawing, Block Elements, Geometric Shapes, Miscellaneous Symbols, Dingbats
491+
(0x2500 <= code_point and code_point <= 0x27BF)
492+
# Miscellaneous Symbols and Pictographs, Ornamental Dingbats, Transport and Map Symbols, Alchemical Symbols
493+
or (0x1F300 <= code_point and code_point <= 0x1F77F)
494+
)
495+
487496
@staticmethod
488497
def _normalize_name(name: str) -> str:
489498
if re.search(NON_NAME_SYMBOL_RE, name):
499+
initially_with_leading_underscore = name.startswith('_')
500+
490501
lang = transliterate.detect_language(name, heavy_check=True)
491502
if lang:
492503
name = transliterate.translit(name, lang, reversed=True)
504+
505+
replacements = {}
506+
for symbol in name:
507+
code_point = ord(symbol)
508+
if Generator._is_emoji(code_point):
509+
replacements[symbol] = f'_u{code_point:X}'
510+
511+
for symbol, replacement in replacements.items():
512+
name = name.replace(symbol, replacement)
513+
493514
name = re.sub(NON_NAME_SYMBOL_RE, '_', name)
515+
516+
if not initially_with_leading_underscore and name.startswith('_'):
517+
name = name[1:]
518+
494519
return name
495520

496521
def _gen_field(
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
definitions:
2+
EnumEmoji:
3+
oneOf:
4+
- $ref: '#/definitions/EnumEmojiThe'
5+
- $ref: '#/definitions/EnumEmojiQuick'
6+
- $ref: '#/definitions/EnumEmojiBrown'
7+
- $ref: '#/definitions/EnumEmojiFox'
8+
- $ref: '#/definitions/EnumEmojiJumps'
9+
- $ref: '#/definitions/EnumEmojiOver'
10+
- $ref: '#/definitions/EnumEmojiLazyDog'
11+
discriminator:
12+
propertyName: emoji
13+
EnumEmojiThe:
14+
type: object
15+
required:
16+
- emoji
17+
properties:
18+
emoji:
19+
type: string
20+
enum: ["👉"]
21+
text:
22+
type: string
23+
default: "the "
24+
additionalProperties: false
25+
EnumEmojiQuick:
26+
type: object
27+
required:
28+
- emoji
29+
properties:
30+
emoji:
31+
type: string
32+
enum: ["⚡"]
33+
text:
34+
type: string
35+
default: "quick "
36+
additionalProperties: false
37+
EnumEmojiBrown:
38+
type: object
39+
required:
40+
- emoji
41+
properties:
42+
emoji:
43+
type: string
44+
enum: ["🟤"]
45+
text:
46+
type: string
47+
default: "brown "
48+
additionalProperties: false
49+
EnumEmojiFox:
50+
type: object
51+
required:
52+
- emoji
53+
properties:
54+
emoji:
55+
type: string
56+
enum: ["🦊"]
57+
text:
58+
type: string
59+
default: "fox "
60+
additionalProperties: false
61+
EnumEmojiJumps:
62+
type: object
63+
required:
64+
- emoji
65+
properties:
66+
emoji:
67+
type: string
68+
enum: ["🦘"]
69+
text:
70+
type: string
71+
default: "jumps "
72+
additionalProperties: false
73+
EnumEmojiOver:
74+
type: object
75+
required:
76+
- emoji
77+
properties:
78+
emoji:
79+
type: string
80+
enum: ["over"]
81+
text:
82+
type: string
83+
default: "over "
84+
additionalProperties: false
85+
EnumEmojiLazyDog:
86+
type: object
87+
required:
88+
- emoji
89+
properties:
90+
emoji:
91+
type: string
92+
enum: ["lazy🐶"]
93+
text:
94+
type: string
95+
default: "lazy dog"
96+
additionalProperties: false
97+
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#include <userver/formats/json/inline.hpp>
2+
#include <userver/utest/assert_macros.hpp>
3+
4+
#include <userver/formats/parse/variant.hpp> // TODO: should work without it
5+
6+
#include <gmock/gmock.h>
7+
8+
#include <string>
9+
#include <vector>
10+
11+
#include <schemas/emoji_enum.hpp>
12+
13+
USERVER_NAMESPACE_BEGIN
14+
15+
TEST(Formatter, EmojiEnum) {
16+
auto obj1 = formats::json::MakeObject("emoji", "👉").As<ns::EnumEmojiThe>();
17+
auto obj2 = formats::json::MakeObject("emoji", "").As<ns::EnumEmoji>();
18+
auto obj3 = formats::json::MakeObject("emoji", "🟤").As<ns::EnumEmoji>();
19+
auto obj4 = formats::json::MakeObject("emoji", "🦊").As<ns::EnumEmoji>();
20+
auto obj5 = formats::json::MakeObject("emoji", "🦘").As<ns::EnumEmoji>();
21+
auto obj6 = formats::json::MakeObject("emoji", "over").As<ns::EnumEmoji>();
22+
auto obj7 = formats::json::MakeObject("emoji", "lazy🐶").As<ns::EnumEmoji>();
23+
std::vector<ns::EnumEmoji> objects{obj1, obj2, obj3, obj4, obj5, obj6, obj7};
24+
25+
std::string phrase;
26+
27+
for (const auto& obj : objects) {
28+
phrase += std::visit([](const auto& item) -> std::string { return item.text; }, obj);
29+
}
30+
EXPECT_EQ(phrase, "the quick brown fox jumps over lazy dog");
31+
}
32+
33+
USERVER_NAMESPACE_END

chaotic/tests/back/cpp/test_tr_object.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,37 @@ def test_field_with_default(simple_gen, cpp_primitive_type):
125125
}
126126

127127

128+
def test_field_escaping(simple_gen, cpp_primitive_type):
129+
schemas = simple_gen({
130+
'type': 'object',
131+
'properties': {'🙂🔥': {'type': 'integer', 'default': 1}},
132+
'additionalProperties': False,
133+
})
134+
assert schemas == {
135+
'::type': cpp_types.CppStruct(
136+
raw_cpp_type=type_name.TypeName('::type'),
137+
json_schema=front_types.Schema(),
138+
nullable=False,
139+
user_cpp_type=None,
140+
# name='vfull#/definitions/type',
141+
fields={
142+
'🙂🔥': cpp_types.CppStructField(
143+
name='u1F642_u1F525',
144+
required=False,
145+
schema=cpp_primitive_type(
146+
validators=cpp_types.CppPrimitiveValidator(
147+
namespace='::type',
148+
prefix='u1F642_u1F525_',
149+
),
150+
raw_cpp_type_str='int',
151+
default=1,
152+
),
153+
),
154+
},
155+
),
156+
}
157+
158+
128159
def test_field_inplace(simple_gen, cpp_primitive_type):
129160
schemas = simple_gen({
130161
'type': 'object',

chaotic/tests/back/cpp/test_tr_string.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,40 @@ def test_enum(simple_gen):
3434
}
3535

3636

37+
def test_enum_emoji(simple_gen):
38+
types = simple_gen({'type': 'string', 'enum': ['🙂', '🔥'], 'default': '🔥'})
39+
assert types == {
40+
'::type': cpp_types.CppStringEnum(
41+
raw_cpp_type=type_name.TypeName('::type'),
42+
user_cpp_type=None,
43+
json_schema=front_types.Schema(),
44+
nullable=False,
45+
name='::type',
46+
default='::type::kU1f525',
47+
enums=[
48+
cpp_types.CppStringEnumItem(raw_name='🙂', cpp_name='kU1f642'),
49+
cpp_types.CppStringEnumItem(raw_name='🔥', cpp_name='kU1f525'),
50+
],
51+
),
52+
}
53+
54+
types = simple_gen({'type': 'string', 'enum': ['❗️ok🜈🙂', '❌ok🜈🔥']})
55+
assert types == {
56+
'::type': cpp_types.CppStringEnum(
57+
raw_cpp_type=type_name.TypeName('::type'),
58+
user_cpp_type=None,
59+
json_schema=front_types.Schema(),
60+
nullable=False,
61+
name='::type',
62+
default=None,
63+
enums=[
64+
cpp_types.CppStringEnumItem(raw_name='❗️ok🜈🙂', cpp_name='kU2757OkU1f708U1f642'),
65+
cpp_types.CppStringEnumItem(raw_name='❌ok🜈🔥', cpp_name='kU274cokU1f708U1f525'),
66+
],
67+
),
68+
}
69+
70+
3771
def test_datetime(simple_gen):
3872
types = simple_gen({'type': 'string', 'format': 'date-time'})
3973
assert types == {

0 commit comments

Comments
 (0)