blob: 057d5d9193275f7726ac0815ba589f0dd7465fc3 [file] [log] [blame]
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define CFC_USE_TEST_MACROS
#include "CFCBase.h"
#include "CFCClass.h"
#include "CFCMethod.h"
#include "CFCParamList.h"
#include "CFCParcel.h"
#include "CFCParser.h"
#include "CFCSymbol.h"
#include "CFCTest.h"
#include "CFCType.h"
#include "CFCUtil.h"
#include "CFCVariable.h"
#ifndef true
#define true 1
#define false 0
#endif
static void
S_run_tests(CFCTest *test);
static void
S_test_initial_value(CFCTest *test, CFCParser *parser,
const char *const *values, const char *type,
const char *test_name);
const CFCTestBatch CFCTEST_BATCH_PARSER = {
"Clownfish::CFC::Model::Parser",
203,
S_run_tests
};
static void
S_run_tests(CFCTest *test) {
CFCParser *parser = CFCParser_new();
OK(test, parser != NULL, "new");
{
CFCParcel *fish = CFCTest_parse_parcel(test, parser, "parcel Fish;");
CFCParcel *registered
= CFCParcel_new("Crustacean", "Crust", NULL, NULL);
CFCParcel_register(registered);
CFCParcel *parcel
= CFCTest_parse_parcel(test, parser, "parcel Crustacean;");
OK(test, parcel == registered, "Fetch registered parcel");
OK(test, CFCParser_get_parcel(parser) == parcel,
"parcel_definition sets internal var");
CFCBase_decref((CFCBase*)fish);
CFCBase_decref((CFCBase*)registered);
CFCBase_decref((CFCBase*)parcel);
}
{
static const char *const specifiers[8] = {
"foo", "_foo", "foo_yoo", "FOO", "Foo", "fOO", "f00", "foo_foo_foo"
};
for (int i = 0; i < 8; ++i) {
const char *specifier = specifiers[i];
char *src = CFCUtil_sprintf("int32_t %s;", specifier);
CFCVariable *var = CFCTest_parse_variable(test, parser, src);
STR_EQ(test, CFCVariable_get_name(var), specifier,
"identifier/declarator: %s", specifier);
FREEMEM(src);
CFCBase_decref((CFCBase*)var);
}
}
{
static const char *const specifiers[6] = {
"void", "float", "uint32_t", "int64_t", "uint8_t", "bool"
};
for (int i = 0; i < 6; ++i) {
const char *specifier = specifiers[i];
char *src = CFCUtil_sprintf("int32_t %s;", specifier);
CFCBase *result = CFCParser_parse(parser, src);
OK(test, result == NULL,
"reserved word not parsed as identifier: %s", specifier);
FREEMEM(src);
CFCBase_decref(result);
}
}
{
static const char *const type_strings[7] = {
"bool", "const char *", "Obj*", "i32_t", "char[]", "long[1]",
"i64_t[30]"
};
for (int i = 0; i < 7; ++i) {
const char *type_string = type_strings[i];
CFCType *type = CFCTest_parse_type(test, parser, type_string);
CFCBase_decref((CFCBase*)type);
}
}
{
static const char *const class_names[7] = {
"ByteBuf", "Obj", "ANDMatcher", "Foo", "FooJr", "FooIII", "Foo4th"
};
CFCClass *class_list[8];
for (int i = 0; i < 7; ++i) {
char *class_code = CFCUtil_sprintf("class %s {}", class_names[i]);
CFCClass *klass = CFCTest_parse_class(test, parser, class_code);
class_list[i] = klass;
FREEMEM(class_code);
}
class_list[7] = NULL;
for (int i = 0; i < 7; ++i) {
const char *class_name = class_names[i];
char *src = CFCUtil_sprintf("%s*", class_name);
char *expected = CFCUtil_sprintf("crust_%s", class_name);
CFCType *type = CFCTest_parse_type(test, parser, src);
CFCType_resolve(type);
STR_EQ(test, CFCType_get_specifier(type), expected,
"object_type_specifier: %s", class_name);
FREEMEM(src);
FREEMEM(expected);
CFCBase_decref((CFCBase*)type);
}
for (int i = 0; i < 7; ++i) {
CFCBase_decref((CFCBase*)class_list[i]);
}
CFCClass_clear_registry();
}
{
CFCType *type = CFCTest_parse_type(test, parser, "const char");
OK(test, CFCType_const(type), "type_qualifier const");
CFCBase_decref((CFCBase*)type);
}
{
static const char *const exposures[2] = {
"public", ""
};
static int (*const accessors[2])(CFCSymbol *sym) = {
CFCSymbol_public, CFCSymbol_parcel
};
for (int i = 0; i < 2; ++i) {
const char *exposure = exposures[i];
char *src = CFCUtil_sprintf("%s inert int32_t foo;", exposure);
CFCVariable *var = CFCTest_parse_variable(test, parser, src);
OK(test, accessors[i]((CFCSymbol*)var), "exposure_specifier %s",
exposure);
FREEMEM(src);
CFCBase_decref((CFCBase*)var);
}
}
{
static const char *const hex_constants[] = {
"0x1", "0x0a", "0xFFFFFFFF", "-0xFC", NULL
};
S_test_initial_value(test, parser, hex_constants, "int32_t",
"hex_constant:");
}
{
static const char *const integer_constants[] = {
"1", "-9999", "0", "10000", NULL
};
S_test_initial_value(test, parser, integer_constants, "int32_t",
"integer_constant:");
}
{
static const char *const float_constants[] = {
"1.0", "-9999.999", "0.1", "0.0", NULL
};
S_test_initial_value(test, parser, float_constants, "double",
"float_constant:");
}
{
static const char *const string_literals[] = {
"\"blah\"", "\"blah blah\"", "\"\\\"blah\\\" \\\"blah\\\"\"", NULL
};
S_test_initial_value(test, parser, string_literals, "String*",
"string_literal:");
}
{
static const char *const composites[5] = {
"int[]", "i32_t **", "Foo **", "Foo ***", "const void *"
};
for (int i = 0; i < 5; ++i) {
const char *composite = composites[i];
CFCType *type = CFCTest_parse_type(test, parser, composite);
OK(test, CFCType_is_composite(type), "composite_type: %s",
composite);
CFCBase_decref((CFCBase*)type);
}
}
{
static const char *const object_types[5] = {
"Obj *", "incremented Foo*", "decremented String *"
};
for (int i = 0; i < 3; ++i) {
const char *object_type = object_types[i];
CFCType *type = CFCTest_parse_type(test, parser, object_type);
OK(test, CFCType_is_object(type), "object_type: %s",
object_type);
CFCBase_decref((CFCBase*)type);
}
}
{
static const char *const param_list_strings[3] = {
"()",
"(int foo)",
"(Obj *foo, Foo **foo_ptr)"
};
for (int i = 0; i < 3; ++i) {
const char *param_list_string = param_list_strings[i];
CFCParamList *param_list
= CFCTest_parse_param_list(test, parser, param_list_string);
INT_EQ(test, CFCParamList_num_vars(param_list), i,
"param list num_vars: %d", i);
CFCBase_decref((CFCBase*)param_list);
}
}
{
CFCParamList *param_list
= CFCTest_parse_param_list(test, parser, "(int foo, ...)");
OK(test, CFCParamList_variadic(param_list), "variadic param list");
CFCBase_decref((CFCBase*)param_list);
}
{
const char *param_list_string =
"(int foo = 0xFF, char *bar =\"blah\")";
CFCParamList *param_list
= CFCTest_parse_param_list(test, parser, param_list_string);
const char **initial_values
= CFCParamList_get_initial_values(param_list);
STR_EQ(test, initial_values[0], "0xFF",
"param list initial_values[0]");
STR_EQ(test, initial_values[1], "\"blah\"",
"param list initial_values[1]");
OK(test, initial_values[2] == NULL, "param list initial_values[2]");
CFCBase_decref((CFCBase*)param_list);
}
{
CFCParser_set_class_name(parser, "Stuff::Obj");
const char *method_string =
"public Foo* Spew_Foo(Obj *self, uint32_t *how_many);";
CFCMethod *method = CFCTest_parse_method(test, parser, method_string);
CFCBase_decref((CFCBase*)method);
const char *var_string =
"public inert Hash *hash;";
CFCVariable *var = CFCTest_parse_variable(test, parser, var_string);
CFCBase_decref((CFCBase*)var);
}
{
static const char *const class_names[4] = {
"Foo", "Foo::FooJr", "Foo::FooJr::FooIII",
"Foo::FooJr::FooIII::Foo4th"
};
for (int i = 0; i < 4; ++i) {
const char *class_name = class_names[i];
char *class_string = CFCUtil_sprintf("class %s { }", class_name);
CFCClass *klass
= CFCTest_parse_class(test, parser, class_string);
STR_EQ(test, CFCClass_get_name(klass), class_name,
"class_name: %s", class_name);
FREEMEM(class_string);
CFCBase_decref((CFCBase*)klass);
}
}
{
static const char *const nicknames[2] = { "Food", "FF" };
for (int i = 0; i < 2; ++i) {
const char *nickname = nicknames[i];
char *class_string
= CFCUtil_sprintf("class Foodie%s nickname %s { }", nickname,
nickname);
CFCClass *klass
= CFCTest_parse_class(test, parser, class_string);
STR_EQ(test, CFCClass_get_nickname(klass), nickname,
"nickname: %s", nickname);
FREEMEM(class_string);
CFCBase_decref((CFCBase*)klass);
}
}
CFCBase_decref((CFCBase*)parser);
CFCClass_clear_registry();
CFCParcel_reap_singletons();
}
static void
S_test_initial_value(CFCTest *test, CFCParser *parser,
const char *const *values, const char *type,
const char *test_name) {
for (int i = 0; values[i]; ++i) {
const char *value = values[i];
char *src = CFCUtil_sprintf("(%s foo = %s)", type, value);
CFCParamList *param_list
= CFCTest_parse_param_list(test, parser, src);
const char **initial_values
= CFCParamList_get_initial_values(param_list);
STR_EQ(test, initial_values[0], value, "%s %s", test_name, value);
FREEMEM(src);
CFCBase_decref((CFCBase*)param_list);
}
}