diff --git a/lib/absinthe/schema/notation.ex b/lib/absinthe/schema/notation.ex index 4d89bb32c4..c964a5a4d2 100644 --- a/lib/absinthe/schema/notation.ex +++ b/lib/absinthe/schema/notation.ex @@ -212,7 +212,12 @@ defmodule Absinthe.Schema.Notation do __CALLER__ |> recordable!(:object, @placement[:object]) - |> record!(Schema.ObjectTypeDefinition, identifier, attrs, block) + |> record!( + Schema.ObjectTypeDefinition, + identifier, + attrs |> Keyword.update(:description, nil, &wrap_in_unquote/1), + block + ) end @placement {:interfaces, [under: [:object]]} @@ -407,6 +412,7 @@ defmodule Absinthe.Schema.Notation do |> expand_ast(caller) |> Keyword.delete(:args) |> Keyword.delete(:meta) + |> Keyword.update(:description, nil, &wrap_in_unquote/1) |> handle_deprecate {attrs, block} @@ -719,7 +725,7 @@ defmodule Absinthe.Schema.Notation do defmacro scalar(identifier, attrs, do: block) do __CALLER__ |> recordable!(:scalar, @placement[:scalar]) - |> record!(Schema.ScalarTypeDefinition, identifier, attrs, block) + |> record_scalar!(identifier, attrs, block) end @doc """ @@ -730,13 +736,13 @@ defmodule Absinthe.Schema.Notation do defmacro scalar(identifier, do: block) do __CALLER__ |> recordable!(:scalar, @placement[:scalar]) - |> record!(Schema.ScalarTypeDefinition, identifier, [], block) + |> record_scalar!(identifier, [], block) end defmacro scalar(identifier, attrs) do __CALLER__ |> recordable!(:scalar, @placement[:scalar]) - |> record!(Schema.ScalarTypeDefinition, identifier, attrs, nil) + |> record_scalar!(identifier, attrs, nil) end @placement {:serialize, [under: [:scalar]]} @@ -934,7 +940,12 @@ defmodule Absinthe.Schema.Notation do defmacro input_object(identifier, attrs \\ [], do: block) do __CALLER__ |> recordable!(:input_object, @placement[:input_object]) - |> record!(Schema.InputObjectTypeDefinition, identifier, attrs, block) + |> record!( + Schema.InputObjectTypeDefinition, + identifier, + attrs |> Keyword.update(:description, nil, &wrap_in_unquote/1), + block + ) end # UNIONS @@ -965,7 +976,12 @@ defmodule Absinthe.Schema.Notation do defmacro union(identifier, attrs \\ [], do: block) do __CALLER__ |> recordable!(:union, @placement[:union]) - |> record!(Schema.UnionTypeDefinition, identifier, attrs, block) + |> record!( + Schema.UnionTypeDefinition, + identifier, + attrs |> Keyword.update(:description, nil, &wrap_in_unquote/1), + block + ) end @placement {:types, [under: [:union]]} @@ -1069,10 +1085,11 @@ defmodule Absinthe.Schema.Notation do |> expand_ast(env) |> Keyword.update(:values, [], fn values -> Enum.map(values, fn ident -> - value_attrs = handle_enum_value_attrs(ident, module: env.module) + value_attrs = handle_enum_value_attrs(ident, [], env) struct!(Schema.EnumValueDefinition, value_attrs) end) end) + |> Keyword.update(:description, nil, &wrap_in_unquote/1) end @placement {:value, [under: [:enum]]} @@ -1296,6 +1313,7 @@ defmodule Absinthe.Schema.Notation do raw_attrs |> Keyword.put_new(:name, to_string(identifier)) |> Keyword.put_new(:type, type) + |> Keyword.update(:description, nil, &wrap_in_unquote/1) |> handle_deprecate end @@ -1319,6 +1337,7 @@ defmodule Absinthe.Schema.Notation do attrs |> Keyword.put(:identifier, identifier) |> Keyword.put_new(:name, to_string(identifier)) + |> Keyword.update(:description, nil, &wrap_in_unquote/1) scoped_def(env, Schema.DirectiveDefinition, identifier, attrs, block) end @@ -1401,16 +1420,27 @@ defmodule Absinthe.Schema.Notation do scoped_def(env, :enum, identifier, attrs, block) end - defp reformat_description(text), do: String.trim(text) - @doc false # Record a description in the current scope def record_description!(env, text_block) do - text = reformat_description(text_block) + text = wrap_in_unquote(text_block) + put_attr(env.module, {:desc, text}) end - def handle_enum_value_attrs(identifier, raw_attrs) do + @doc false + # Record a scalar + def record_scalar!(env, identifier, attrs, block_or_nil) do + record!( + env, + Schema.ScalarTypeDefinition, + identifier, + attrs |> Keyword.update(:description, nil, &wrap_in_unquote/1), + block_or_nil + ) + end + + def handle_enum_value_attrs(identifier, raw_attrs, env) do value = case Keyword.get(raw_attrs, :as, identifier) do value when is_tuple(value) -> @@ -1423,18 +1453,19 @@ defmodule Absinthe.Schema.Notation do end raw_attrs - |> expand_ast(raw_attrs) + |> expand_ast(env) |> Keyword.put(:identifier, identifier) |> Keyword.put(:value, value) |> Keyword.put_new(:name, String.upcase(to_string(identifier))) |> Keyword.delete(:as) + |> Keyword.update(:description, nil, &wrap_in_unquote/1) |> handle_deprecate end @doc false # Record an enum value in the current scope def record_value!(env, identifier, raw_attrs) do - attrs = handle_enum_value_attrs(identifier, raw_attrs) + attrs = handle_enum_value_attrs(identifier, raw_attrs, env) record!(env, Schema.EnumValueDefinition, identifier, attrs, []) end @@ -1445,7 +1476,7 @@ defmodule Absinthe.Schema.Notation do values |> expand_ast(env) |> Enum.map(fn ident -> - value_attrs = handle_enum_value_attrs(ident, module: env.module) + value_attrs = handle_enum_value_attrs(ident, [], env) struct!(Schema.EnumValueDefinition, value_attrs) end) @@ -1484,6 +1515,14 @@ defmodule Absinthe.Schema.Notation do put_attr(env.module, {:middleware, [new_middleware]}) end + # We wrap the value (from the user) in an `unquote` call, so that when the schema `blueprint` is + # placed into `__absinthe_blueprint__` via `unquote(Macro.escape(blueprint, unquote: true))` the + # value get's unquoted. This allows us to evaluate function calls in the scope of the schema + # module. + defp wrap_in_unquote(value) do + {:unquote, [], [value]} + end + # ------------------------------ @doc false @@ -1866,6 +1905,18 @@ defmodule Absinthe.Schema.Notation do defp expand_ast(ast, env) do Macro.prewalk(ast, fn + # We don't want to expand `@bla` into `Module.get_attribute(module, @bla)` because this + # function call will fail if the module is already compiled. Remember that the ast gets put + # into a generated `__absinthe_blueprint__` function which is called at "__after_compile__" + # time. This will be after a module has been compiled if there are multiple modules in the + # schema (in the case of an `import_types`). + # + # Also see test "test/absinthe/type/import_types_test.exs" + # "__absinthe_blueprint__ is callable at runtime even if there is a module attribute" + # and it's comment for more information + {:@, _, _} = node -> + node + {_, _, _} = node -> Macro.expand(node, env) diff --git a/test/absinthe/execution/arguments/scalar_test.exs b/test/absinthe/execution/arguments/scalar_test.exs index 384551d489..e0f3226d66 100644 --- a/test/absinthe/execution/arguments/scalar_test.exs +++ b/test/absinthe/execution/arguments/scalar_test.exs @@ -1,6 +1,8 @@ defmodule Absinthe.Execution.Arguments.ScalarTest do use Absinthe.Case, async: true + alias Absinthe.Blueprint.Input + alias Absinthe.Fixtures.Scalar @schema Absinthe.Fixtures.ArgumentsSchema @@ -58,4 +60,45 @@ defmodule Absinthe.Execution.Arguments.ScalarTest do ) end end + + describe "scalar keyword description evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = Scalar.TestSchemaDescriptionKeyword.__absinthe_type__(unquote(test_label)) + assert type.description == unquote(expected_value) + end + end) + end + + describe "scalar description attribute evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Absinthe.Fixtures.FunctionEvaluationHelpers.filter_test_params_for_description_attribute() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = Scalar.TestSchemaDescriptionAttribute.__absinthe_type__(unquote(test_label)) + + assert type.description == unquote(expected_value) + end + end) + end + + describe "scalar description macro evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = Scalar.TestSchemaDescriptionMacro.__absinthe_type__(unquote(test_label)) + assert type.description == unquote(expected_value) + end + end) + end end diff --git a/test/absinthe/type/directive_test.exs b/test/absinthe/type/directive_test.exs index a0b438529d..a547a2adcb 100644 --- a/test/absinthe/type/directive_test.exs +++ b/test/absinthe/type/directive_test.exs @@ -2,6 +2,7 @@ defmodule Absinthe.Type.DirectiveTest do use Absinthe.Case, async: true alias Absinthe.Schema + alias Absinthe.Fixtures.Directive defmodule TestSchema do use Absinthe.Schema @@ -224,4 +225,61 @@ defmodule Absinthe.Type.DirectiveTest do Absinthe.run(@query, Absinthe.Fixtures.ContactSchema) end end + + describe "directive keyword description evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = Directive.TestSchemaDescriptionKeyword.__absinthe_directive__(unquote(test_label)) + assert type.description == unquote(expected_value) + end + end) + end + + describe "directive description attribute evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Absinthe.Fixtures.FunctionEvaluationHelpers.filter_test_params_for_description_attribute() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = + Directive.TestSchemaDescriptionAttribute.__absinthe_directive__(unquote(test_label)) + + assert type.description == unquote(expected_value) + end + end) + end + + describe "directive description macro evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = Directive.TestSchemaDescriptionMacro.__absinthe_directive__(unquote(test_label)) + assert type.description == unquote(expected_value) + end + end) + end + + describe "directive arg keyword description evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = + Directive.TestSchemaArgDescriptionKeyword.__absinthe_directive__(unquote(test_label)) + + assert type.args[:arg_example].description == unquote(expected_value) + end + end) + end end diff --git a/test/absinthe/type/enum_test.exs b/test/absinthe/type/enum_test.exs index 1a6cc02c14..98dc8a0114 100644 --- a/test/absinthe/type/enum_test.exs +++ b/test/absinthe/type/enum_test.exs @@ -2,6 +2,7 @@ defmodule Absinthe.Type.EnumTest do use Absinthe.Case, async: true alias Absinthe.Type + alias Absinthe.Fixtures.Enums defmodule TestSchema do use Absinthe.Schema @@ -71,4 +72,59 @@ defmodule Absinthe.Type.EnumTest do assert %Type.Enum.Value{name: "RED", value: :red, description: nil} = type.values[:red] end end + + describe "enum value description evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = + Enums.TestSchemaValueDescriptionKeyword.__absinthe_type__(:description_keyword_argument) + + assert type.values[unquote(test_label)].description == unquote(expected_value) + end + end) + end + + describe "enum description keyword evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = Enums.TestSchemaDescriptionKeyword.__absinthe_type__(unquote(test_label)) + assert type.description == unquote(expected_value) + end + end) + end + + describe "enum description attribute evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Absinthe.Fixtures.FunctionEvaluationHelpers.filter_test_params_for_description_attribute() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = Enums.TestSchemaDescriptionAttribute.__absinthe_type__(unquote(test_label)) + assert type.description == unquote(expected_value) + end + end) + end + + describe "enum description macro evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = Enums.TestSchemaDescriptionMacro.__absinthe_type__(unquote(test_label)) + assert type.description == unquote(expected_value) + end + end) + end end diff --git a/test/absinthe/type/import_types_test.exs b/test/absinthe/type/import_types_test.exs index a0c01a9900..491dd59f52 100644 --- a/test/absinthe/type/import_types_test.exs +++ b/test/absinthe/type/import_types_test.exs @@ -39,4 +39,55 @@ defmodule Absinthe.Type.ImportTypesTest do assert Absinthe.Schema.lookup_type(ImportTypes.SelfContainedSchema, :role_enum) end end + + describe "import_types with description function evaluation (in input_object field description)" do + # The module attribute iteration of this test is related to the test below. + # See "__absinthe_blueprint__ is callable at runtime even if there is a module attribute" for more + # information + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = ImportTypes.SchemaWithFunctionEvaluation.__absinthe_type__(:example_input_object) + + assert type.fields[unquote(test_label)].description == unquote(expected_value) + end + end) + + # From inside `defp expand_ast` in `Absinthe.Schema.Notation`: + # + # > We don't want to expand `@bla` into `Module.get_attribute(module, @bla)` because this + # > function call will fail if the module is already compiled. Remember that the ast gets put + # > into a generated `__absinthe_blueprint__` function which is called at "__after_compile__" + # > time. This will be after a module has been compiled if there are multiple modules in the + # > schema (in the case of an `import_types`). + # + # This test checks that __absinthe_blueprint__ runs and doesn't raise an error saying + # "Module.get_attribute" cannot be called because the module is already compiled". This error + # happens because the `@module_attribute` gets expanded by `expand_ast` into + # `Module.get_attribute(Absinthe.Fixtures.ImportTypes.SchemaWithModuleAttribute, + # :module_attribute, )`. + # + # We ensure __absinthe_blueprint__ is runnable at runtime because in projects where the schema + # is split into multiple modules, one of the modules may already have completely finished + # compiling, dumping the Module attribute data (they are baked in to the code at compile time) + # which means that the `Module.get_attribute` call will raise the error mentioned above + # + # Above, test "works with module attribute used in imported module" also checks this same + # functionality + # + test "__absinthe_blueprint__ is callable at runtime even if there is a module attribute" do + # Sanity check. Shouldn't ever really fail (unless something is very wrong), but ensures that + # the assertion makes sense + {:module, ImportTypes.SchemaWithFunctionEvaluation} = + Code.ensure_compiled(ImportTypes.SchemaWithFunctionEvaluation) + + assert match?( + %Absinthe.Blueprint{}, + ImportTypes.SchemaWithFunctionEvaluation.__absinthe_blueprint__() + ) + end + end end diff --git a/test/absinthe/type/input_object_test.exs b/test/absinthe/type/input_object_test.exs index 4857ec7a45..d4e9659124 100644 --- a/test/absinthe/type/input_object_test.exs +++ b/test/absinthe/type/input_object_test.exs @@ -1,6 +1,8 @@ defmodule Absinthe.Type.InputObjectTest do use Absinthe.Case, async: true + alias Absinthe.Fixtures.InputObject + defmodule Schema do use Absinthe.Schema @@ -28,4 +30,94 @@ defmodule Absinthe.Type.InputObjectTest do assert %Absinthe.Type.Field{name: "name", type: :string} = obj.fields.name end end + + describe "input object keyword description evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = InputObject.TestSchemaDescriptionKeyword.__absinthe_type__(unquote(test_label)) + assert type.description == unquote(expected_value) + end + end) + end + + describe "input_object description attribute evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Absinthe.Fixtures.FunctionEvaluationHelpers.filter_test_params_for_description_attribute() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = InputObject.TestSchemaDescriptionAttribute.__absinthe_type__(unquote(test_label)) + assert type.description == unquote(expected_value) + end + end) + end + + describe "input_object description macro evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = InputObject.TestSchemaDescriptionMacro.__absinthe_type__(unquote(test_label)) + assert type.description == unquote(expected_value) + end + end) + end + + describe "input object field keyword description evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = + InputObject.TestSchemaFieldsAndArgsDescription.__absinthe_type__( + :description_keyword_argument + ) + + assert type.fields[unquote(test_label)].description == unquote(expected_value) + end + end) + end + + describe "input object field attribute description evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Absinthe.Fixtures.FunctionEvaluationHelpers.filter_test_params_for_description_attribute() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = + InputObject.TestSchemaFieldsAndArgsDescription.__absinthe_type__(:description_attribute) + + assert type.fields[unquote(test_label)].description == unquote(expected_value) + end + end) + end + + describe "input object field macro description evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = + InputObject.TestSchemaFieldsAndArgsDescription.__absinthe_type__( + :field_description_macro + ) + + assert type.fields[unquote(test_label)].description == unquote(expected_value) + end + end) + end end diff --git a/test/absinthe/type/mutation_test.exs b/test/absinthe/type/mutation_test.exs new file mode 100644 index 0000000000..50e55918af --- /dev/null +++ b/test/absinthe/type/mutation_test.exs @@ -0,0 +1,72 @@ +defmodule Absinthe.Type.MutationTest do + use Absinthe.Case, async: true + + defmodule TestSchema do + use Absinthe.Schema + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + def test_function(arg1) do + arg1 + end + + query do + end + + mutation do + field :normal_string, :string do + arg :arg_example, :string, description: "string" + end + + field :local_function_call, :string do + arg :arg_example, :string, description: test_function("red") + end + + field :function_call_using_absolute_path_to_current_module, :string do + arg :arg_example, :string, + description: Absinthe.Type.MutationTest.TestSchema.test_function("red") + end + + field :standard_library_function, :string do + arg :arg_example, :string, description: String.replace("red", "e", "a") + end + + field :function_in_nested_module, :string do + arg :arg_example, :string, description: NestedModule.nested_function("hello") + end + + field :external_module_function_call, :string do + arg :arg_example, :string, + description: Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") + end + + field :module_attribute_string_concat, :string do + arg :arg_example, :string, description: "hello " <> @module_attribute + end + + field :interpolation_of_module_attribute, :string do + arg :arg_example, :string, description: "hello #{@module_attribute}" + end + end + end + + describe "mutation field arg keyword description evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = TestSchema.__absinthe_type__("RootMutationType") + + assert type.fields[unquote(test_label)].args.arg_example.description == + unquote(expected_value) + end + end) + end +end diff --git a/test/absinthe/type/object_test.exs b/test/absinthe/type/object_test.exs index 079add7b57..2ebf04a91a 100644 --- a/test/absinthe/type/object_test.exs +++ b/test/absinthe/type/object_test.exs @@ -1,6 +1,8 @@ defmodule Absinthe.Type.ObjectTest do use Absinthe.Case, async: true + alias Absinthe.Fixtures.Object + defmodule Schema do use Absinthe.Schema @@ -40,4 +42,91 @@ defmodule Absinthe.Type.ObjectTest do assert %Absinthe.Type.Argument{name: "height", type: :integer} = field.args.height end end + + describe "input object keyword description evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = Object.TestSchemaDescriptionKeyword.__absinthe_type__(unquote(test_label)) + assert type.description == unquote(expected_value) + end + end) + end + + describe "input_object description attribute evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Absinthe.Fixtures.FunctionEvaluationHelpers.filter_test_params_for_description_attribute() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = Object.TestSchemaDescriptionAttribute.__absinthe_type__(unquote(test_label)) + assert type.description == unquote(expected_value) + end + end) + end + + describe "input_object description macro evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = Object.TestSchemaDescriptionMacro.__absinthe_type__(unquote(test_label)) + assert type.description == unquote(expected_value) + end + end) + end + + describe "input object field keyword description evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = + Object.TestSchemaFieldsAndArgsDescription.__absinthe_type__( + :description_keyword_argument + ) + + assert type.fields[unquote(test_label)].description == unquote(expected_value) + end + end) + end + + describe "input object field attribute description evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Absinthe.Fixtures.FunctionEvaluationHelpers.filter_test_params_for_description_attribute() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = Object.TestSchemaFieldsAndArgsDescription.__absinthe_type__(:description_attribute) + + assert type.fields[unquote(test_label)].description == unquote(expected_value) + end + end) + end + + describe "input object field macro description evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = + Object.TestSchemaFieldsAndArgsDescription.__absinthe_type__(:field_description_macro) + + assert type.fields[unquote(test_label)].description == unquote(expected_value) + end + end) + end end diff --git a/test/absinthe/type/query_test.exs b/test/absinthe/type/query_test.exs new file mode 100644 index 0000000000..adb1798b39 --- /dev/null +++ b/test/absinthe/type/query_test.exs @@ -0,0 +1,69 @@ +defmodule Absinthe.Type.QueryTest do + use Absinthe.Case, async: true + + defmodule TestSchema do + use Absinthe.Schema + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + def test_function(arg1) do + arg1 + end + + query do + field :normal_string, :string do + arg :arg_example, :string, description: "string" + end + + field :local_function_call, :string do + arg :arg_example, :string, description: test_function("red") + end + + field :function_call_using_absolute_path_to_current_module, :string do + arg :arg_example, :string, + description: Absinthe.Type.QueryTest.TestSchema.test_function("red") + end + + field :standard_library_function, :string do + arg :arg_example, :string, description: String.replace("red", "e", "a") + end + + field :function_in_nested_module, :string do + arg :arg_example, :string, description: NestedModule.nested_function("hello") + end + + field :external_module_function_call, :string do + arg :arg_example, :string, + description: Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") + end + + field :module_attribute_string_concat, :string do + arg :arg_example, :string, description: "hello " <> @module_attribute + end + + field :interpolation_of_module_attribute, :string do + arg :arg_example, :string, description: "hello #{@module_attribute}" + end + end + end + + describe "query field arg keyword description evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = TestSchema.__absinthe_type__("RootQueryType") + + assert type.fields[unquote(test_label)].args.arg_example.description == + unquote(expected_value) + end + end) + end +end diff --git a/test/absinthe/type/union_test.exs b/test/absinthe/type/union_test.exs index e889b12399..074bef85d9 100644 --- a/test/absinthe/type/union_test.exs +++ b/test/absinthe/type/union_test.exs @@ -2,6 +2,7 @@ defmodule Absinthe.Type.UnionTest do use Absinthe.Case, async: true alias Absinthe.Type + alias Absinthe.Fixtures.Union defmodule TestSchema do use Absinthe.Schema @@ -82,4 +83,45 @@ defmodule Absinthe.Type.UnionTest do Type.Union.resolve_type(obj, %{name: "asdf"}, %{schema: TestSchema}) end end + + describe "union keyword description evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = Union.TestSchemaDescriptionKeyword.__absinthe_type__(unquote(test_label)) + assert type.description == unquote(expected_value) + end + end) + end + + describe "union description attribute evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Absinthe.Fixtures.FunctionEvaluationHelpers.filter_test_params_for_description_attribute() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = Union.TestSchemaDescriptionAttribute.__absinthe_type__(unquote(test_label)) + + assert type.description == unquote(expected_value) + end + end) + end + + describe "union description macro evaluation" do + Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params() + |> Enum.each(fn %{ + test_label: test_label, + expected_value: expected_value + } -> + test "for #{test_label} (evaluates description to '#{expected_value}')" do + type = Union.TestSchemaDescriptionMacro.__absinthe_type__(unquote(test_label)) + assert type.description == unquote(expected_value) + end + end) + end end diff --git a/test/support/fixtures/directive.ex b/test/support/fixtures/directive.ex new file mode 100644 index 0000000000..911b631738 --- /dev/null +++ b/test/support/fixtures/directive.ex @@ -0,0 +1,235 @@ +defmodule Absinthe.Fixtures.Directive do + defmodule TestSchemaDescriptionKeyword do + use Absinthe.Schema + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + query do + end + + directive :normal_string, description: "string" do + on [:field] + end + + directive :local_function_call, description: test_function("red") do + on [:field] + end + + directive :function_call_using_absolute_path_to_current_module, + description: Absinthe.Fixtures.Directive.TestSchemaDescriptionKeyword.test_function("red") do + on [:field] + end + + directive :standard_library_function, description: String.replace("red", "e", "a") do + on [:field] + end + + directive :function_in_nested_module, description: NestedModule.nested_function("hello") do + on [:field] + end + + directive :external_module_function_call, + description: Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") do + on [:field] + end + + directive :module_attribute_string_concat, description: "hello " <> @module_attribute do + on [:field] + end + + directive :interpolation_of_module_attribute, description: "hello #{@module_attribute}" do + on [:field] + end + + def test_function(arg1) do + arg1 + end + end + + defmodule TestSchemaDescriptionAttribute do + use Absinthe.Schema + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + query do + end + + def test_function(arg1) do + arg1 + end + + @desc "string" + directive :normal_string do + on [:field] + end + + # These tests do not work as test_function is not available at compile time, and the + # expression for the @desc attribute is evaluated at compile time. There is nothing we can + # really do about it + + # @desc test_function("red") + # directive :local_function_call do + # on [:field] + # end + + # @desc Absinthe.Fixtures.Directive.TestSchemaEnumAttribute.test_function("red") + # directive :function_call_using_absolute_path_to_current_module do + # on [:field] + # end + + @desc String.replace("red", "e", "a") + directive :standard_library_function do + on [:field] + end + + @desc NestedModule.nested_function("hello") + directive :function_in_nested_module do + on [:field] + end + + @desc Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") + directive :external_module_function_call do + on [:field] + end + + @desc "hello " <> @module_attribute + directive :module_attribute_string_concat do + on [:field] + end + + @desc "hello #{@module_attribute}" + directive :interpolation_of_module_attribute do + on [:field] + end + end + + defmodule TestSchemaDescriptionMacro do + use Absinthe.Schema + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + query do + end + + def test_function(arg1) do + arg1 + end + + directive :normal_string do + on [:field] + description "string" + end + + directive :local_function_call do + on [:field] + description test_function("red") + end + + directive :function_call_using_absolute_path_to_current_module do + on [:field] + description Absinthe.Fixtures.Directive.TestSchemaDescriptionMacro.test_function("red") + end + + directive :standard_library_function do + on [:field] + description String.replace("red", "e", "a") + end + + directive :function_in_nested_module do + on [:field] + description NestedModule.nested_function("hello") + end + + directive :external_module_function_call do + on [:field] + description Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") + end + + directive :module_attribute_string_concat do + on [:field] + description "hello " <> @module_attribute + end + + directive :interpolation_of_module_attribute do + on [:field] + description "hello #{@module_attribute}" + end + end + + defmodule TestSchemaArgDescriptionKeyword do + use Absinthe.Schema + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + query do + end + + directive :normal_string do + arg :arg_example, :string, description: "string" + on [:field] + end + + directive :local_function_call do + arg :arg_example, :string, description: test_function("red") + on [:field] + end + + directive :function_call_using_absolute_path_to_current_module do + arg :arg_example, :string, + description: Absinthe.Fixtures.Directive.TestSchemaDescriptionKeyword.test_function("red") + + on [:field] + end + + directive :standard_library_function do + arg :arg_example, :string, description: String.replace("red", "e", "a") + on [:field] + end + + directive :function_in_nested_module do + arg :arg_example, :string, description: NestedModule.nested_function("hello") + on [:field] + end + + directive :external_module_function_call do + arg :arg_example, :string, + description: Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") + + on [:field] + end + + directive :module_attribute_string_concat do + arg :arg_example, :string, description: "hello " <> @module_attribute + on [:field] + end + + directive :interpolation_of_module_attribute do + arg :arg_example, :string, description: "hello #{@module_attribute}" + on [:field] + end + + def test_function(arg1) do + arg1 + end + end +end diff --git a/test/support/fixtures/enums.ex b/test/support/fixtures/enums.ex new file mode 100644 index 0000000000..d4d3083624 --- /dev/null +++ b/test/support/fixtures/enums.ex @@ -0,0 +1,185 @@ +defmodule Absinthe.Fixtures.Enums do + defmodule TestSchemaValueDescriptionKeyword do + use Absinthe.Schema + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + query do + end + + def test_function(arg1) do + arg1 + end + + enum :description_keyword_argument do + value :normal_string, description: "string" + value :local_function_call, description: test_function("red") + + value :function_call_using_absolute_path_to_current_module, + description: + Absinthe.Fixtures.Enums.TestSchemaValueDescriptionKeyword.test_function("red") + + value :standard_library_function, description: String.replace("red", "e", "a") + value :function_in_nested_module, description: NestedModule.nested_function("hello") + + value :external_module_function_call, + description: Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") + + value :module_attribute_string_concat, description: "hello " <> @module_attribute + value :interpolation_of_module_attribute, description: "hello #{@module_attribute}" + end + end + + defmodule TestSchemaDescriptionKeyword do + use Absinthe.Schema + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + query do + end + + enum :normal_string, description: "string" do + end + + enum :local_function_call, description: test_function("red") do + end + + enum :function_call_using_absolute_path_to_current_module, + description: Absinthe.Fixtures.Enums.TestSchemaDescriptionKeyword.test_function("red") do + end + + enum :standard_library_function, description: String.replace("red", "e", "a") do + end + + enum :function_in_nested_module, description: NestedModule.nested_function("hello") do + end + + enum :external_module_function_call, + description: Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") do + end + + enum :module_attribute_string_concat, description: "hello " <> @module_attribute do + end + + enum :interpolation_of_module_attribute, description: "hello #{@module_attribute}" do + end + + def test_function(arg1) do + arg1 + end + end + + defmodule TestSchemaDescriptionAttribute do + use Absinthe.Schema + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + query do + end + + def test_function(arg1) do + arg1 + end + + @desc "string" + enum :normal_string do + end + + # These tests do not work as test_function is not available at compile time, and the + # expression for the @desc attribute is evaluated at compile time. There is nothing we can + # really do about it + + # @desc test_function("red") + # enum :local_function_call do + # end + + # @desc Absinthe.Fixtures.Enums.TestSchemaEnumAttribute.test_function("red") + # enum :function_call_using_absolute_path_to_current_module do + # end + + @desc String.replace("red", "e", "a") + enum :standard_library_function do + end + + @desc NestedModule.nested_function("hello") + enum :function_in_nested_module do + end + + @desc Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") + enum :external_module_function_call do + end + + @desc "hello " <> @module_attribute + enum :module_attribute_string_concat do + end + + @desc "hello #{@module_attribute}" + enum :interpolation_of_module_attribute do + end + end + + defmodule TestSchemaDescriptionMacro do + use Absinthe.Schema + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + query do + end + + def test_function(arg1) do + arg1 + end + + enum :normal_string do + description "string" + end + + enum :local_function_call do + description test_function("red") + end + + enum :function_call_using_absolute_path_to_current_module do + description Absinthe.Fixtures.Enums.TestSchemaDescriptionMacro.test_function("red") + end + + enum :standard_library_function do + description String.replace("red", "e", "a") + end + + enum :function_in_nested_module do + description NestedModule.nested_function("hello") + end + + enum :external_module_function_call do + description Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") + end + + enum :module_attribute_string_concat do + description "hello " <> @module_attribute + end + + enum :interpolation_of_module_attribute do + description "hello #{@module_attribute}" + end + end +end diff --git a/test/support/fixtures/function_evaluation_helpers.ex b/test/support/fixtures/function_evaluation_helpers.ex new file mode 100644 index 0000000000..efcdcb0865 --- /dev/null +++ b/test/support/fixtures/function_evaluation_helpers.ex @@ -0,0 +1,30 @@ +defmodule Absinthe.Fixtures.FunctionEvaluationHelpers do + def function_evaluation_test_params do + [ + %{test_label: :normal_string, expected_value: "string"}, + %{test_label: :local_function_call, expected_value: "red"}, + %{test_label: :function_call_using_absolute_path_to_current_module, expected_value: "red"}, + %{test_label: :standard_library_function, expected_value: "rad"}, + %{test_label: :function_in_nested_module, expected_value: "hello"}, + %{test_label: :external_module_function_call, expected_value: "the value is hello"}, + %{test_label: :module_attribute_string_concat, expected_value: "hello goodbye"}, + %{test_label: :interpolation_of_module_attribute, expected_value: "hello goodbye"} + ] + end + + # These tests do not work as test_function is not available at compile time, and the + # expression for the @desc attribute is evaluated at compile time. There is nothing we can + # really do about it + def filter_test_params_for_description_attribute(test_params) do + Enum.filter(test_params, fn %{test_label: test_label} -> + test_label not in [ + :local_function_call, + :function_call_using_absolute_path_to_current_module + ] + end) + end + + def external_function(arg) do + "the value is #{arg}" + end +end diff --git a/test/support/fixtures/import_types.ex b/test/support/fixtures/import_types.ex index 97e0b249ad..5210ba5a3b 100644 --- a/test/support/fixtures/import_types.ex +++ b/test/support/fixtures/import_types.ex @@ -165,4 +165,48 @@ defmodule Absinthe.Fixtures.ImportTypes do field :credit_cards, list_of(:credit_card) end end + + defmodule SchemaWithFunctionEvaluationImports do + use Absinthe.Schema.Notation + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + def test_function(arg1) do + arg1 + end + + input_object :example_input_object do + field :normal_string, :string, description: "string" + field :local_function_call, :string, description: test_function("red") + + field :function_call_using_absolute_path_to_current_module, :string, + description: + Absinthe.Fixtures.ImportTypes.SchemaWithFunctionEvaluationImports.test_function("red") + + field :standard_library_function, :string, description: String.replace("red", "e", "a") + + field :function_in_nested_module, :string, + description: NestedModule.nested_function("hello") + + field :external_module_function_call, :string, + description: Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") + + field :module_attribute_string_concat, :string, description: "hello " <> @module_attribute + field :interpolation_of_module_attribute, :string, description: "hello #{@module_attribute}" + end + end + + defmodule SchemaWithFunctionEvaluation do + use Absinthe.Schema + + import_types(SchemaWithFunctionEvaluationImports) + + query do + end + end end diff --git a/test/support/fixtures/input_object.ex b/test/support/fixtures/input_object.ex new file mode 100644 index 0000000000..9267a3cd04 --- /dev/null +++ b/test/support/fixtures/input_object.ex @@ -0,0 +1,255 @@ +defmodule Absinthe.Fixtures.InputObject do + defmodule TestSchemaDescriptionKeyword do + use Absinthe.Schema + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + query do + end + + input_object :normal_string, description: "string" do + end + + input_object :local_function_call, description: test_function("red") do + end + + input_object :function_call_using_absolute_path_to_current_module, + description: Absinthe.Fixtures.InputObject.TestSchemaDescriptionKeyword.test_function("red") do + end + + input_object :standard_library_function, description: String.replace("red", "e", "a") do + end + + input_object :function_in_nested_module, description: NestedModule.nested_function("hello") do + end + + input_object :external_module_function_call, + description: Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") do + end + + input_object :module_attribute_string_concat, description: "hello " <> @module_attribute do + end + + input_object :interpolation_of_module_attribute, description: "hello #{@module_attribute}" do + end + + def test_function(arg1) do + arg1 + end + end + + defmodule TestSchemaDescriptionAttribute do + use Absinthe.Schema + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + query do + end + + def test_function(arg1) do + arg1 + end + + @desc "string" + input_object :normal_string do + end + + # These tests do not work as test_function is not available at compile time, and the + # expression for the @desc attribute is evaluated at compile time. There is nothing we can + # really do about it + + # @desc test_function("red") + # input_object :local_function_call do + # end + + # @desc Absinthe.Fixtures.InputObject.TestSchemaAttribute.test_function("red") + # input_object :function_call_using_absolute_path_to_current_module do + # end + + @desc String.replace("red", "e", "a") + input_object :standard_library_function do + end + + @desc NestedModule.nested_function("hello") + input_object :function_in_nested_module do + end + + @desc Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") + input_object :external_module_function_call do + end + + @desc "hello " <> @module_attribute + input_object :module_attribute_string_concat do + end + + @desc "hello #{@module_attribute}" + input_object :interpolation_of_module_attribute do + end + end + + defmodule TestSchemaDescriptionMacro do + use Absinthe.Schema + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + query do + end + + def test_function(arg1) do + arg1 + end + + input_object :normal_string do + description "string" + end + + input_object :local_function_call do + description test_function("red") + end + + input_object :function_call_using_absolute_path_to_current_module do + description Absinthe.Fixtures.InputObject.TestSchemaDescriptionMacro.test_function("red") + end + + input_object :standard_library_function do + description String.replace("red", "e", "a") + end + + input_object :function_in_nested_module do + description NestedModule.nested_function("hello") + end + + input_object :external_module_function_call do + description Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") + end + + input_object :module_attribute_string_concat do + description "hello " <> @module_attribute + end + + input_object :interpolation_of_module_attribute do + description "hello #{@module_attribute}" + end + end + + defmodule TestSchemaFieldsAndArgsDescription do + use Absinthe.Schema + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + query do + end + + def test_function(arg1) do + arg1 + end + + input_object :description_keyword_argument do + field :normal_string, :string, description: "string" + field :local_function_call, :string, description: test_function("red") + + field :function_call_using_absolute_path_to_current_module, :string, + description: + Absinthe.Fixtures.InputObject.TestSchemaFieldsAndArgsDescription.test_function("red") + + field :standard_library_function, :string, description: String.replace("red", "e", "a") + + field :function_in_nested_module, :string, + description: NestedModule.nested_function("hello") + + field :external_module_function_call, :string, + description: Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") + + field :module_attribute_string_concat, :string, description: "hello " <> @module_attribute + field :interpolation_of_module_attribute, :string, description: "hello #{@module_attribute}" + end + + input_object :description_attribute do + @desc "string" + field :normal_string, :string + + # These tests do not work as test_function is not available at compile time, and the + # expression for the @desc attribute is evaluated at compile time. There is nothing we can + # really do about it + + # @desc test_function("red") + # field :local_function_call, :string + + # @desc Absinthe.Fixtures.InputObject.TestSchemaFieldsAndArgsDescription.test_function( + # "red" + # ) + # field :function_call_using_absolute_path_to_current_module, :string + + @desc String.replace("red", "e", "a") + field :standard_library_function, :string + + @desc NestedModule.nested_function("hello") + field :function_in_nested_module, :string + + @desc Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") + field :external_module_function_call, :string + + @desc "hello " <> @module_attribute + field :module_attribute_string_concat, :string + + @desc "hello #{@module_attribute}" + field :interpolation_of_module_attribute, :string + end + + input_object :field_description_macro do + field :normal_string, :string do + description "string" + end + + field :local_function_call, :string do + description test_function("red") + end + + field :function_call_using_absolute_path_to_current_module, :string do + description Absinthe.Fixtures.InputObject.TestSchemaFieldsAndArgsDescription.test_function( + "red" + ) + end + + field :standard_library_function, :string do + description String.replace("red", "e", "a") + end + + field :function_in_nested_module, :string do + description NestedModule.nested_function("hello") + end + + field :external_module_function_call, :string do + description Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") + end + + field :module_attribute_string_concat, :string do + description "hello " <> @module_attribute + end + + field :interpolation_of_module_attribute, :string do + description "hello #{@module_attribute}" + end + end + end +end diff --git a/test/support/fixtures/object.ex b/test/support/fixtures/object.ex new file mode 100644 index 0000000000..bcba7e18f8 --- /dev/null +++ b/test/support/fixtures/object.ex @@ -0,0 +1,255 @@ +defmodule Absinthe.Fixtures.Object do + defmodule TestSchemaDescriptionKeyword do + use Absinthe.Schema + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + query do + end + + object :normal_string, description: "string" do + end + + object :local_function_call, description: test_function("red") do + end + + object :function_call_using_absolute_path_to_current_module, + description: Absinthe.Fixtures.Object.TestSchemaDescriptionKeyword.test_function("red") do + end + + object :standard_library_function, description: String.replace("red", "e", "a") do + end + + object :function_in_nested_module, description: NestedModule.nested_function("hello") do + end + + object :external_module_function_call, + description: Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") do + end + + object :module_attribute_string_concat, description: "hello " <> @module_attribute do + end + + object :interpolation_of_module_attribute, description: "hello #{@module_attribute}" do + end + + def test_function(arg1) do + arg1 + end + end + + defmodule TestSchemaDescriptionAttribute do + use Absinthe.Schema + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + query do + end + + def test_function(arg1) do + arg1 + end + + @desc "string" + object :normal_string do + end + + # These tests do not work as test_function is not available at compile time, and the + # expression for the @desc attribute is evaluated at compile time. There is nothing we can + # really do about it + + # @desc test_function("red") + # object :local_function_call do + # end + + # @desc Absinthe.Fixtures.Object.TestSchemaAttribute.test_function("red") + # object :function_call_using_absolute_path_to_current_module do + # end + + @desc String.replace("red", "e", "a") + object :standard_library_function do + end + + @desc NestedModule.nested_function("hello") + object :function_in_nested_module do + end + + @desc Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") + object :external_module_function_call do + end + + @desc "hello " <> @module_attribute + object :module_attribute_string_concat do + end + + @desc "hello #{@module_attribute}" + object :interpolation_of_module_attribute do + end + end + + defmodule TestSchemaDescriptionMacro do + use Absinthe.Schema + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + query do + end + + def test_function(arg1) do + arg1 + end + + object :normal_string do + description "string" + end + + object :local_function_call do + description test_function("red") + end + + object :function_call_using_absolute_path_to_current_module do + description Absinthe.Fixtures.Object.TestSchemaDescriptionMacro.test_function("red") + end + + object :standard_library_function do + description String.replace("red", "e", "a") + end + + object :function_in_nested_module do + description NestedModule.nested_function("hello") + end + + object :external_module_function_call do + description Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") + end + + object :module_attribute_string_concat do + description "hello " <> @module_attribute + end + + object :interpolation_of_module_attribute do + description "hello #{@module_attribute}" + end + end + + defmodule TestSchemaFieldsAndArgsDescription do + use Absinthe.Schema + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + query do + end + + def test_function(arg1) do + arg1 + end + + object :description_keyword_argument do + field :normal_string, :string, description: "string" + field :local_function_call, :string, description: test_function("red") + + field :function_call_using_absolute_path_to_current_module, :string, + description: + Absinthe.Fixtures.Object.TestSchemaFieldsAndArgsDescription.test_function("red") + + field :standard_library_function, :string, description: String.replace("red", "e", "a") + + field :function_in_nested_module, :string, + description: NestedModule.nested_function("hello") + + field :external_module_function_call, :string, + description: Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") + + field :module_attribute_string_concat, :string, description: "hello " <> @module_attribute + field :interpolation_of_module_attribute, :string, description: "hello #{@module_attribute}" + end + + object :description_attribute do + @desc "string" + field :normal_string, :string + + # These tests do not work as test_function is not available at compile time, and the + # expression for the @desc attribute is evaluated at compile time. There is nothing we can + # really do about it + + # @desc test_function("red") + # field :local_function_call, :string + + # @desc Absinthe.Fixtures.Object.TestSchemaFieldsAndArgsDescription.test_function( + # "red" + # ) + # field :function_call_using_absolute_path_to_current_module, :string + + @desc String.replace("red", "e", "a") + field :standard_library_function, :string + + @desc NestedModule.nested_function("hello") + field :function_in_nested_module, :string + + @desc Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") + field :external_module_function_call, :string + + @desc "hello " <> @module_attribute + field :module_attribute_string_concat, :string + + @desc "hello #{@module_attribute}" + field :interpolation_of_module_attribute, :string + end + + object :field_description_macro do + field :normal_string, :string do + description "string" + end + + field :local_function_call, :string do + description test_function("red") + end + + field :function_call_using_absolute_path_to_current_module, :string do + description Absinthe.Fixtures.Object.TestSchemaFieldsAndArgsDescription.test_function( + "red" + ) + end + + field :standard_library_function, :string do + description String.replace("red", "e", "a") + end + + field :function_in_nested_module, :string do + description NestedModule.nested_function("hello") + end + + field :external_module_function_call, :string do + description Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") + end + + field :module_attribute_string_concat, :string do + description "hello " <> @module_attribute + end + + field :interpolation_of_module_attribute, :string do + description "hello #{@module_attribute}" + end + end + end +end diff --git a/test/support/fixtures/scalar.ex b/test/support/fixtures/scalar.ex new file mode 100644 index 0000000000..b2ba80bb06 --- /dev/null +++ b/test/support/fixtures/scalar.ex @@ -0,0 +1,202 @@ +defmodule Absinthe.Fixtures.Scalar do + defmodule Utils do + def parse(value), do: value + def serialize(value), do: value + end + + defmodule TestSchemaDescriptionKeyword do + use Absinthe.Schema + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + query do + end + + scalar :normal_string, description: "string" do + parse &Utils.parse/1 + serialize &Utils.serialize/1 + end + + scalar :local_function_call, description: test_function("red") do + parse &Utils.parse/1 + serialize &Utils.serialize/1 + end + + scalar :function_call_using_absolute_path_to_current_module, + description: Absinthe.Fixtures.Scalar.TestSchemaDescriptionKeyword.test_function("red") do + parse &Utils.parse/1 + serialize &Utils.serialize/1 + end + + scalar :standard_library_function, description: String.replace("red", "e", "a") do + parse &Utils.parse/1 + serialize &Utils.serialize/1 + end + + scalar :function_in_nested_module, description: NestedModule.nested_function("hello") do + parse &Utils.parse/1 + serialize &Utils.serialize/1 + end + + scalar :external_module_function_call, + description: Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") do + parse &Utils.parse/1 + serialize &Utils.serialize/1 + end + + scalar :module_attribute_string_concat, description: "hello " <> @module_attribute do + parse &Utils.parse/1 + serialize &Utils.serialize/1 + end + + scalar :interpolation_of_module_attribute, description: "hello #{@module_attribute}" do + parse &Utils.parse/1 + serialize &Utils.serialize/1 + end + + def test_function(arg1) do + arg1 + end + end + + defmodule TestSchemaDescriptionAttribute do + use Absinthe.Schema + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + query do + end + + def test_function(arg1) do + arg1 + end + + @desc "string" + scalar :normal_string do + parse &Utils.parse/1 + serialize &Utils.serialize/1 + end + + # These tests do not work as test_function is not available at compile time, and the + # expression for the @desc attribute is evaluated at compile time. There is nothing we can + # really do about it + + # @desc test_function("red") + # scalar :local_function_call do + # parse &Utils.parse/1 + # serialize &Utils.serialize/1 + # end + + # @desc Absinthe.Fixtures.Scalar.TestSchemaEnumAttribute.test_function("red") + # scalar :function_call_using_absolute_path_to_current_module do + # parse &Utils.parse/1 + # serialize &Utils.serialize/1 + # end + + @desc String.replace("red", "e", "a") + scalar :standard_library_function do + parse &Utils.parse/1 + serialize &Utils.serialize/1 + end + + @desc NestedModule.nested_function("hello") + scalar :function_in_nested_module do + parse &Utils.parse/1 + serialize &Utils.serialize/1 + end + + @desc Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") + scalar :external_module_function_call do + parse &Utils.parse/1 + serialize &Utils.serialize/1 + end + + @desc "hello " <> @module_attribute + scalar :module_attribute_string_concat do + parse &Utils.parse/1 + serialize &Utils.serialize/1 + end + + @desc "hello #{@module_attribute}" + scalar :interpolation_of_module_attribute do + parse &Utils.parse/1 + serialize &Utils.serialize/1 + end + end + + defmodule TestSchemaDescriptionMacro do + use Absinthe.Schema + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + query do + end + + def test_function(arg1) do + arg1 + end + + scalar :normal_string do + parse &Utils.parse/1 + serialize &Utils.serialize/1 + description "string" + end + + scalar :local_function_call do + parse &Utils.parse/1 + serialize &Utils.serialize/1 + description test_function("red") + end + + scalar :function_call_using_absolute_path_to_current_module do + parse &Utils.parse/1 + serialize &Utils.serialize/1 + description Absinthe.Fixtures.Scalar.TestSchemaDescriptionMacro.test_function("red") + end + + scalar :standard_library_function do + parse &Utils.parse/1 + serialize &Utils.serialize/1 + description String.replace("red", "e", "a") + end + + scalar :function_in_nested_module do + parse &Utils.parse/1 + serialize &Utils.serialize/1 + description NestedModule.nested_function("hello") + end + + scalar :external_module_function_call do + parse &Utils.parse/1 + serialize &Utils.serialize/1 + description Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") + end + + scalar :module_attribute_string_concat do + parse &Utils.parse/1 + serialize &Utils.serialize/1 + description "hello " <> @module_attribute + end + + scalar :interpolation_of_module_attribute do + parse &Utils.parse/1 + serialize &Utils.serialize/1 + description "hello #{@module_attribute}" + end + end +end diff --git a/test/support/fixtures/union.ex b/test/support/fixtures/union.ex new file mode 100644 index 0000000000..51cd4ad936 --- /dev/null +++ b/test/support/fixtures/union.ex @@ -0,0 +1,151 @@ +defmodule Absinthe.Fixtures.Union do + defmodule TestSchemaDescriptionKeyword do + use Absinthe.Schema + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + query do + end + + union :normal_string, description: "string" do + end + + union :local_function_call, description: test_function("red") do + end + + union :function_call_using_absolute_path_to_current_module, + description: Absinthe.Fixtures.Union.TestSchemaDescriptionKeyword.test_function("red") do + end + + union :standard_library_function, description: String.replace("red", "e", "a") do + end + + union :function_in_nested_module, description: NestedModule.nested_function("hello") do + end + + union :external_module_function_call, + description: Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") do + end + + union :module_attribute_string_concat, description: "hello " <> @module_attribute do + end + + union :interpolation_of_module_attribute, description: "hello #{@module_attribute}" do + end + + def test_function(arg1) do + arg1 + end + end + + defmodule TestSchemaDescriptionAttribute do + use Absinthe.Schema + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + query do + end + + def test_function(arg1) do + arg1 + end + + @desc "string" + union :normal_string do + end + + # These tests do not work as test_function is not available at compile time, and the + # expression for the @desc attribute is evaluated at compile time. There is nothing we can + # really do about it + + # @desc test_function("red") + # union :local_function_call do + + # end + + # @desc Absinthe.Fixtures.Union.TestSchemaEnumAttribute.test_function("red") + # union :function_call_using_absolute_path_to_current_module do + + # end + + @desc String.replace("red", "e", "a") + union :standard_library_function do + end + + @desc NestedModule.nested_function("hello") + union :function_in_nested_module do + end + + @desc Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") + union :external_module_function_call do + end + + @desc "hello " <> @module_attribute + union :module_attribute_string_concat do + end + + @desc "hello #{@module_attribute}" + union :interpolation_of_module_attribute do + end + end + + defmodule TestSchemaDescriptionMacro do + use Absinthe.Schema + @module_attribute "goodbye" + + defmodule NestedModule do + def nested_function(arg1) do + arg1 + end + end + + query do + end + + def test_function(arg1) do + arg1 + end + + union :normal_string do + description "string" + end + + union :local_function_call do + description test_function("red") + end + + union :function_call_using_absolute_path_to_current_module do + description Absinthe.Fixtures.Union.TestSchemaDescriptionMacro.test_function("red") + end + + union :standard_library_function do + description String.replace("red", "e", "a") + end + + union :function_in_nested_module do + description NestedModule.nested_function("hello") + end + + union :external_module_function_call do + description Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello") + end + + union :module_attribute_string_concat do + description "hello " <> @module_attribute + end + + union :interpolation_of_module_attribute do + description "hello #{@module_attribute}" + end + end +end