diff --git a/src/mango/test/23-explain-indexes-test.py b/src/mango/test/23-explain-indexes-test.py deleted file mode 100644 index b023a9e9df3..00000000000 --- a/src/mango/test/23-explain-indexes-test.py +++ /dev/null @@ -1,447 +0,0 @@ -# Licensed 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. - -import mango -import user_docs -import unittest - - -class ExplainIndexJSONTests(mango.UserDocsTests): - def test_basic(self): - resp = self.db.find({"age": 23}, explain=True) - candidate_indexes = [ - { - "index": { - "ddoc": "_design/user_id", - "name": "user_id", - "type": "json", - "partitioned": False, - "def": {"fields": [{"user_id": "asc"}]}, - }, - "analysis": { - "usable": False, - "reasons": [{"name": "field_mismatch"}], - "ranking": 2, - "covering": False, - }, - }, - { - "index": { - "ddoc": "_design/twitter", - "name": "twitter", - "type": "json", - "partitioned": False, - "def": {"fields": [{"twitter": "asc"}]}, - }, - "analysis": { - "usable": False, - "reasons": [{"name": "field_mismatch"}], - "ranking": 2, - "covering": False, - }, - }, - { - "index": { - "ddoc": "_design/ordered", - "name": "ordered", - "type": "json", - "partitioned": False, - "def": {"fields": [{"ordered": "asc"}]}, - }, - "analysis": { - "usable": False, - "reasons": [{"name": "field_mismatch"}], - "ranking": 2, - "covering": False, - }, - }, - { - "index": { - "ddoc": "_design/name", - "name": "name", - "type": "json", - "partitioned": False, - "def": {"fields": [{"name.last": "asc"}, {"name.first": "asc"}]}, - }, - "analysis": { - "usable": False, - "reasons": [{"name": "field_mismatch"}], - "ranking": 2, - "covering": False, - }, - }, - { - "index": { - "ddoc": "_design/manager", - "name": "manager", - "type": "json", - "partitioned": False, - "def": {"fields": [{"manager": "asc"}]}, - }, - "analysis": { - "usable": False, - "reasons": [{"name": "field_mismatch"}], - "ranking": 2, - "covering": False, - }, - }, - { - "index": { - "ddoc": "_design/location", - "name": "location", - "type": "json", - "partitioned": False, - "def": { - "fields": [ - {"location.state": "asc"}, - {"location.city": "asc"}, - {"location.address.street": "asc"}, - {"location.address.number": "asc"}, - ] - }, - }, - "analysis": { - "usable": False, - "reasons": [{"name": "field_mismatch"}], - "ranking": 2, - "covering": False, - }, - }, - { - "index": { - "ddoc": "_design/favorites_3", - "name": "favorites_3", - "type": "json", - "partitioned": False, - "def": {"fields": [{"favorites.3": "asc"}]}, - }, - "analysis": { - "usable": False, - "reasons": [{"name": "field_mismatch"}], - "ranking": 2, - "covering": False, - }, - }, - { - "index": { - "ddoc": "_design/favorites", - "name": "favorites", - "type": "json", - "partitioned": False, - "def": {"fields": [{"favorites": "asc"}]}, - }, - "analysis": { - "usable": False, - "reasons": [{"name": "field_mismatch"}], - "ranking": 2, - "covering": False, - }, - }, - { - "index": { - "ddoc": "_design/company_and_manager", - "name": "company_and_manager", - "type": "json", - "partitioned": False, - "def": {"fields": [{"company": "asc"}, {"manager": "asc"}]}, - }, - "analysis": { - "usable": False, - "reasons": [{"name": "field_mismatch"}], - "ranking": 2, - "covering": False, - }, - }, - { - "index": { - "ddoc": None, - "name": "_all_docs", - "type": "special", - "def": {"fields": [{"_id": "asc"}]}, - }, - "analysis": { - "usable": True, - "reasons": [{"name": "unfavored_type"}], - "ranking": 1, - "covering": None, - }, - }, - ] - with self.subTest(subject="index_candidates"): - assert resp["index_candidates"] == candidate_indexes - with self.subTest(subject="selector_hints"): - selector_hints = resp["selector_hints"][0] - assert selector_hints == { - "type": "json", - "indexable_fields": ["age"], - "unindexable_fields": [], - } - - -class ExplainIndexTestsNoIndexes(mango.UserDocsTestsNoIndexes): - def test_basic(self): - resp = self.db.find({"age": 23}, explain=True) - assert resp["index_candidates"] == [] - assert resp["index"] != None - assert resp["partitioned"] == False - - def test_no_usable_index(self): - resp = self.db.find({"age": 23}, sort=["company"], explain=True) - candidate_indexes = [ - { - "index": { - "ddoc": None, - "name": "_all_docs", - "type": "special", - "def": {"fields": [{"_id": "asc"}]}, - }, - "analysis": { - "usable": False, - "reasons": [{"name": "field_mismatch"}], - "ranking": 1, - "covering": None, - }, - } - ] - assert resp["index_candidates"] == candidate_indexes - assert resp["index"] == None - assert resp["partitioned"] == False - - -@unittest.skipUnless(mango.has_text_service(), "requires text service") -class ExplainIndexTextTests(mango.UserDocsTextTests): - def test_basic(self): - resp = self.db.find({"age": 23}, explain=True) - candidate_indexes = [ - { - "index": { - "ddoc": None, - "name": "_all_docs", - "type": "special", - "def": {"fields": [{"_id": "asc"}]}, - }, - "analysis": { - "usable": True, - "reasons": [{"name": "unfavored_type"}], - "ranking": 1, - "covering": None, - }, - } - ] - with self.subTest(subject="index_candidates"): - assert resp["index_candidates"] == candidate_indexes - with self.subTest(subject="selector_hints"): - selector_hints = resp["selector_hints"] - assert selector_hints == [ - {"type": "json", "indexable_fields": ["age"], "unindexable_fields": []}, - {"type": "text", "indexable_fields": ["age"], "unindexable_fields": []}, - ] - - -@unittest.skipUnless(mango.has_text_service(), "requires text service") -class ExplainIndexMixedTests(mango.DbPerClass): - @classmethod - def setUpClass(klass): - super(ExplainIndexMixedTests, klass).setUpClass() - user_docs.setup(klass.db) - klass.db.create_text_index() - - def test_basic(self): - resp = self.db.find({"age": 23}, explain=True) - candidate_indexes = [ - { - "index": { - "ddoc": "_design/user_id", - "name": "user_id", - "type": "json", - "partitioned": False, - "def": {"fields": [{"user_id": "asc"}]}, - }, - "analysis": { - "usable": False, - "reasons": [{"name": "field_mismatch"}], - "ranking": 2, - "covering": False, - }, - }, - { - "index": { - "ddoc": "_design/twitter", - "name": "twitter", - "type": "json", - "partitioned": False, - "def": {"fields": [{"twitter": "asc"}]}, - }, - "analysis": { - "usable": False, - "reasons": [{"name": "field_mismatch"}], - "ranking": 2, - "covering": False, - }, - }, - { - "index": { - "ddoc": "_design/ordered", - "name": "ordered", - "type": "json", - "partitioned": False, - "def": {"fields": [{"ordered": "asc"}]}, - }, - "analysis": { - "usable": False, - "reasons": [{"name": "field_mismatch"}], - "ranking": 2, - "covering": False, - }, - }, - { - "index": { - "ddoc": "_design/name", - "name": "name", - "type": "json", - "partitioned": False, - "def": {"fields": [{"name.last": "asc"}, {"name.first": "asc"}]}, - }, - "analysis": { - "usable": False, - "reasons": [{"name": "field_mismatch"}], - "ranking": 2, - "covering": False, - }, - }, - { - "index": { - "ddoc": "_design/manager", - "name": "manager", - "type": "json", - "partitioned": False, - "def": {"fields": [{"manager": "asc"}]}, - }, - "analysis": { - "usable": False, - "reasons": [{"name": "field_mismatch"}], - "ranking": 2, - "covering": False, - }, - }, - { - "index": { - "ddoc": "_design/location", - "name": "location", - "type": "json", - "partitioned": False, - "def": { - "fields": [ - {"location.state": "asc"}, - {"location.city": "asc"}, - {"location.address.street": "asc"}, - {"location.address.number": "asc"}, - ] - }, - }, - "analysis": { - "usable": False, - "reasons": [{"name": "field_mismatch"}], - "ranking": 2, - "covering": False, - }, - }, - { - "index": { - "ddoc": "_design/favorites_3", - "name": "favorites_3", - "type": "json", - "partitioned": False, - "def": {"fields": [{"favorites.3": "asc"}]}, - }, - "analysis": { - "usable": False, - "reasons": [{"name": "field_mismatch"}], - "ranking": 2, - "covering": False, - }, - }, - { - "index": { - "ddoc": "_design/favorites", - "name": "favorites", - "type": "json", - "partitioned": False, - "def": {"fields": [{"favorites": "asc"}]}, - }, - "analysis": { - "usable": False, - "reasons": [{"name": "field_mismatch"}], - "ranking": 2, - "covering": False, - }, - }, - { - "index": { - "ddoc": "_design/company_and_manager", - "name": "company_and_manager", - "type": "json", - "partitioned": False, - "def": {"fields": [{"company": "asc"}, {"manager": "asc"}]}, - }, - "analysis": { - "usable": False, - "reasons": [{"name": "field_mismatch"}], - "ranking": 2, - "covering": False, - }, - }, - { - "index": { - "ddoc": "_design/cedc01a027213706d7260b5e5b73c70b9233743a", - "name": "cedc01a027213706d7260b5e5b73c70b9233743a", - "type": "text", - "partitioned": False, - "def": { - "default_analyzer": "keyword", - "default_field": {}, - "selector": {}, - "fields": [], - "index_array_lengths": True, - }, - }, - "analysis": { - "usable": True, - "reasons": [{"name": "unfavored_type"}], - "ranking": 1, - "covering": None, - }, - }, - { - "index": { - "ddoc": None, - "name": "_all_docs", - "type": "special", - "def": {"fields": [{"_id": "asc"}]}, - }, - "analysis": { - "usable": True, - "reasons": [{"name": "unfavored_type"}], - "ranking": 1, - "covering": None, - }, - }, - ] - assert resp["index_candidates"] == candidate_indexes - - -class ExplainIndexTestsPartitionedNoIndexes(mango.PartitionedUserDocsTestsNoIndexes): - def test_basic(self): - resp = self.db.find({"age": 23}, explain=True) - assert resp["index_candidates"] == [] - assert resp["index"] != None - assert resp["partitioned"] == True diff --git a/test/elixir/test/config/search.elixir b/test/elixir/test/config/search.elixir index 87715d4caf3..c858ed1232f 100644 --- a/test/elixir/test/config/search.elixir +++ b/test/elixir/test/config/search.elixir @@ -38,5 +38,12 @@ ], "LimitTests": [ "limit field" + ], + "ExplainIndexTextTests": [ + "basic index candidates", + "basic selector hints" + ], + "ExplainIndexMixedTests": [ + "basic" ] } diff --git a/test/elixir/test/config/suite.elixir b/test/elixir/test/config/suite.elixir index b3fb950846c..f4aa033f04c 100644 --- a/test/elixir/test/config/suite.elixir +++ b/test/elixir/test/config/suite.elixir @@ -735,5 +735,16 @@ ], "IgnoreDesignDocsForAllDocsIndexTests": [ "should not return design docs" + ], + "ExplainIndexJSONTests": [ + "basic index candidates", + "basic selector hints" + ], + "ExplainIndexTestsNoIndexes": [ + "basic", + "no usable index" + ], + "ExplainIndexTestsPartitionedNoIndexes": [ + "basic" ] } diff --git a/test/elixir/test/mango/23_explain_indexes_test.exs b/test/elixir/test/mango/23_explain_indexes_test.exs new file mode 100644 index 00000000000..e36e32e3a1e --- /dev/null +++ b/test/elixir/test/mango/23_explain_indexes_test.exs @@ -0,0 +1,494 @@ +# Licensed 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. + +defmodule ExplainIndexJSONTests do + use CouchTestCase + + @db_name "explain-indexes" + + @candidate_indexes [ + %{ + "index" => %{ + "ddoc" => "_design/user_id", + "name" => "user_id", + "type" => "json", + "partitioned" => false, + "def" => %{"fields" => [%{"user_id" => "asc"}]}, + }, + "analysis" => %{ + "usable" => false, + "reasons" => [%{"name" => "field_mismatch"}], + "ranking" => 2, + "covering" => false, + } + }, + %{ + "index" => %{ + "ddoc" => "_design/twitter", + "name" => "twitter", + "type" => "json", + "partitioned" => false, + "def" => %{"fields" => [%{"twitter" => "asc"}]}, + }, + "analysis" => %{ + "usable" => false, + "reasons" => [%{"name" => "field_mismatch"}], + "ranking" => 2, + "covering" => false, + } + }, + %{ + "index" => %{ + "ddoc" => "_design/ordered", + "name" => "ordered", + "type" => "json", + "partitioned" => false, + "def" => %{"fields" => [%{"ordered" => "asc"}]}, + }, + "analysis" => %{ + "usable" => false, + "reasons" => [%{"name" => "field_mismatch"}], + "ranking" => 2, + "covering" => false, + } + }, + %{ + "index" => %{ + "ddoc" => "_design/name", + "name" => "name", + "type" => "json", + "partitioned" => false, + "def" => %{"fields" => [%{"name.last" => "asc"}, %{"name.first" => "asc"}]}, + }, + "analysis" => %{ + "usable" => false, + "reasons" => [%{"name" => "field_mismatch"}], + "ranking" => 2, + "covering" => false, + } + }, + %{ + "index" => %{ + "ddoc" => "_design/manager", + "name" => "manager", + "type" => "json", + "partitioned" => false, + "def" => %{"fields" => [%{"manager" => "asc"}]}, + }, + "analysis" => %{ + "usable" => false, + "reasons" => [%{"name" => "field_mismatch"}], + "ranking" => 2, + "covering" => false, + } + }, + %{ + "index" => %{ + "ddoc" => "_design/location", + "name" => "location", + "type" => "json", + "partitioned" => false, + "def" => %{ + "fields" => [ + %{"location.state" => "asc"}, + %{"location.city" => "asc"}, + %{"location.address.street" => "asc"}, + %{"location.address.number" => "asc"}, + ] + }, + }, + "analysis" => %{ + "usable" => false, + "reasons" => [%{"name" => "field_mismatch"}], + "ranking" => 2, + "covering" => false, + }, + }, + %{ + "index" => %{ + "ddoc" => "_design/favorites_3", + "name" => "favorites_3", + "type" => "json", + "partitioned" => false, + "def" => %{"fields" => [%{"favorites.3" => "asc"}]}, + }, + "analysis" => %{ + "usable" => false, + "reasons" => [%{"name" => "field_mismatch"}], + "ranking" => 2, + "covering" => false, + }, + }, + %{ + "index" => %{ + "ddoc" => "_design/favorites", + "name" => "favorites", + "type" => "json", + "partitioned" => false, + "def" => %{"fields" => [%{"favorites" => "asc"}]}, + }, + "analysis" => %{ + "usable" => false, + "reasons" => [%{"name" => "field_mismatch"}], + "ranking" => 2, + "covering" => false, + }, + }, + %{ + "index" => %{ + "ddoc" => "_design/company_and_manager", + "name" => "company_and_manager", + "type" => "json", + "partitioned" => false, + "def" => %{"fields" => [%{"company" => "asc"}, %{"manager" => "asc"}]}, + }, + "analysis" => %{ + "usable" => false, + "reasons" => [%{"name" => "field_mismatch"}], + "ranking" => 2, + "covering" => false, + }, + }, + %{ + "index" => %{ + "ddoc" => nil, + "name" => "_all_docs", + "type" => "special", + "def" => %{"fields" => [%{"_id" => "asc"}]}, + }, + "analysis" => %{ + "usable" => true, + "reasons" => [%{"name" => "unfavored_type"}], + "ranking" => 1, + "covering" => nil, + } + } + ] + + setup do + UserDocs.setup(@db_name) + end + + test "basic index candidates" do + {:ok, explain} = MangoDatabase.find(@db_name, %{"age" => 23}, explain: true) + + assert explain["index_candidates"] == @candidate_indexes + end + + test "basic selector hints" do + {:ok, explain} = MangoDatabase.find(@db_name, %{"age" => 23}, explain: true) + + selector_hints = Enum.at(explain["selector_hints"], 0) + assert selector_hints == %{ + "type" => "json", + "indexable_fields" => ["age"], + "unindexable_fields" => [], + } + end +end + +defmodule ExplainIndexTestsNoIndexes do + use CouchTestCase + + @db_name "explain-indexes-noindex" + + setup do + UserDocs.setup(@db_name, "special") + end + + test "basic" do + {:ok, explain} = MangoDatabase.find(@db_name, %{"age" => 23}, explain: true) + + assert explain["index_candidates"] == [] + assert explain["index"] != nil + assert explain["partitioned"] == false + end + + test "no usable index" do + {:ok, explain} = MangoDatabase.find(@db_name, %{"age" => 23}, sort: ["company"], explain: true) + + candidate_indexes = [%{ + "index" => %{ + "ddoc" => nil, + "name" => "_all_docs", + "type" => "special", + "def" => %{"fields" => [%{"_id" => "asc"}]} + }, + "analysis" => %{ + "usable" => false, + "reasons" => [%{"name" => "field_mismatch"}], + "ranking" => 1, + "covering" => nil, + } + }] + + assert explain["index_candidates"] == candidate_indexes + assert explain["index"] == nil + assert explain["partitioned"] == false + end +end + +defmodule ExplainIndexTextTests do + use CouchTestCase + + @db_name "explain-indexes-text" + + setup do + UserDocs.setup(@db_name, "text") + end + + test "basic index candidates" do + candidate_indexes = [ + %{ + "index" => %{ + "ddoc" => nil, + "name" => "_all_docs", + "type" => "special", + "def" => %{"fields" => [%{"_id" => "asc"}]}, + }, + "analysis" => %{ + "usable" => true, + "reasons" => [%{"name" => "unfavored_type"}], + "ranking" => 1, + "covering" => nil, + } + } + ] + {:ok, explain} = MangoDatabase.find(@db_name, %{"age" => 23}, explain: true) + + assert explain["index_candidates"] == candidate_indexes + end + + test "basic selector hints" do + {:ok, explain} = MangoDatabase.find(@db_name, %{"age" => 23}, explain: true) + + selector_hints = explain["selector_hints"] + assert selector_hints == [ + %{"type" => "json", "indexable_fields" => ["age"], "unindexable_fields" => []}, + %{"type" => "text", "indexable_fields" => ["age"], "unindexable_fields" => []}, + ] + end +end + +defmodule ExplainIndexMixedTests do + use CouchTestCase + + @db_name "explain-indexes-mixed" + + setup do + UserDocs.setup(@db_name) + MangoDatabase.create_text_index(@db_name) + :ok + end + + test "basic" do + candidate_indexes = [ + %{ + "index" => %{ + "ddoc" => "_design/user_id", + "name" => "user_id", + "type" => "json", + "partitioned" => false, + "def" => %{"fields" => [%{"user_id" => "asc"}]}, + }, + "analysis" => %{ + "usable" => false, + "reasons" => [%{"name" => "field_mismatch"}], + "ranking" => 2, + "covering" => false, + }, + }, + %{ + "index" => %{ + "ddoc" => "_design/twitter", + "name" => "twitter", + "type" => "json", + "partitioned" => false, + "def" => %{"fields" => [%{"twitter" => "asc"}]}, + }, + "analysis" => %{ + "usable" => false, + "reasons" => [%{"name" => "field_mismatch"}], + "ranking" => 2, + "covering" => false, + }, + }, + %{ + "index" => %{ + "ddoc" => "_design/ordered", + "name" => "ordered", + "type" => "json", + "partitioned" => false, + "def" => %{"fields" => [%{"ordered" => "asc"}]}, + }, + "analysis" => %{ + "usable" => false, + "reasons" => [%{"name" => "field_mismatch"}], + "ranking" => 2, + "covering" => false, + }, + }, + %{ + "index" => %{ + "ddoc" => "_design/name", + "name" => "name", + "type" => "json", + "partitioned" => false, + "def" => %{"fields" => [%{"name.last" => "asc"}, %{"name.first" => "asc"}]}, + }, + "analysis" => %{ + "usable" => false, + "reasons" => [%{"name" => "field_mismatch"}], + "ranking" => 2, + "covering" => false, + }, + }, + %{ + "index" => %{ + "ddoc" => "_design/manager", + "name" => "manager", + "type" => "json", + "partitioned" => false, + "def" => %{"fields" => [%{"manager" => "asc"}]}, + }, + "analysis" => %{ + "usable" => false, + "reasons" => [%{"name" => "field_mismatch"}], + "ranking" => 2, + "covering" => false, + }, + }, + %{ + "index" => %{ + "ddoc" => "_design/location", + "name" => "location", + "type" => "json", + "partitioned" => false, + "def" => %{ + "fields" => [ + %{"location.state" => "asc"}, + %{"location.city" => "asc"}, + %{"location.address.street" => "asc"}, + %{"location.address.number" => "asc"}, + ] + }, + }, + "analysis" => %{ + "usable" => false, + "reasons" => [%{"name" => "field_mismatch"}], + "ranking" => 2, + "covering" => false, + }, + }, + %{ + "index" => %{ + "ddoc" => "_design/favorites_3", + "name" => "favorites_3", + "type" => "json", + "partitioned" => false, + "def" => %{"fields" => [%{"favorites.3" => "asc"}]}, + }, + "analysis" => %{ + "usable" => false, + "reasons" => [%{"name" => "field_mismatch"}], + "ranking" => 2, + "covering" => false, + }, + }, + %{ + "index" => %{ + "ddoc" => "_design/favorites", + "name" => "favorites", + "type" => "json", + "partitioned" => false, + "def" => %{"fields" => [%{"favorites" => "asc"}]}, + }, + "analysis" => %{ + "usable" => false, + "reasons" => [%{"name" => "field_mismatch"}], + "ranking" => 2, + "covering" => false, + }, + }, + %{ + "index" => %{ + "ddoc" => "_design/company_and_manager", + "name" => "company_and_manager", + "type" => "json", + "partitioned" => false, + "def" => %{"fields" => [%{"company" => "asc"}, %{"manager" => "asc"}]}, + }, + "analysis" => %{ + "usable" => false, + "reasons" => [%{"name" => "field_mismatch"}], + "ranking" => 2, + "covering" => false, + }, + }, + %{ + "index" => %{ + "ddoc" => "_design/cedc01a027213706d7260b5e5b73c70b9233743a", + "name" => "cedc01a027213706d7260b5e5b73c70b9233743a", + "type" => "text", + "partitioned" => false, + "def" => %{ + "default_analyzer" => "keyword", + "default_field" => %{}, + "selector" => %{}, + "fields" => [], + "index_array_lengths" => true, + }, + }, + "analysis" => %{ + "usable" => true, + "reasons" => [%{"name" => "unfavored_type"}], + "ranking" => 1, + "covering" => nil, + }, + }, + %{ + "index" => %{ + "ddoc" => nil, + "name" => "_all_docs", + "type" => "special", + "def" => %{"fields" => [%{"_id" => "asc"}]}, + }, + "analysis" => %{ + "usable" => true, + "reasons" => [%{"name" => "unfavored_type"}], + "ranking" => 1, + "covering" => nil, + }, + }] + {:ok, explain} = MangoDatabase.find(@db_name, %{"age" => 23}, explain: true) + + assert explain["index_candidates"] == candidate_indexes + end +end + +defmodule ExplainIndexTestsPartitionedNoIndexes do + use CouchTestCase + + @db_name "explain-indexes-part-noindex" + + setup do + UserDocs.setup(@db_name, "special", true) + end + + test "basic" do + {:ok, explain} = MangoDatabase.find(@db_name, %{"age" => 23}, explain: true) + + assert explain["index_candidates"] == [] + assert explain["index"] != nil + assert explain["partitioned"] == true + end +end