xUnitFor1C icon indicating copy to clipboard operation
xUnitFor1C copied to clipboard

Сравнение коллекций

Open wwall opened this issue 10 years ago • 24 comments

Речь пока идет только об обработке УтвержденияBDD

Что имеем - умеет сравнивать только примитивные типы. Это хорошо. Не умеет сравнивать коллекции. Это плохо, потому как чаще всего надо именно коллекции сравнивать (по крайней мере мне). Как я вижу сравнение? Есть тест - Процедура ТестПроверкиРавенстваСтруктур() Экспорт

СтруктураПроверки = новый Структура;
СтруктураПроверки.Вставить("Поле",1);
СтруктураПроверки.Вставить("Поле2",новый Структура("Поле3",4));

СтруктураПроверки2 = новый Структура;
СтруктураПроверки2.Вставить("Поле",1);
СтруктураПроверки2.Вставить("Поле2",новый Структура("Поле3",4));

Ожидаем.Что(СтруктураПроверки).Равно(СтруктураПроверки2);

КонецПроцедуры

Как видно - пытаемся сравнить 2 структуры (взяты для простоты, остальные коллекции аналогично работают)

Предлагая сделать так - результат сравнения не булево, а структура, примерно так

Функция Ок(значение) возврат Новый Структура("Тип,Результат",1,Значение) КонецФункции

Функция Ошибка(значение) возврат Новый Структура("Тип,Результат",0,Значение) КонецФункции

функция Проверить2Значения(Проверяемое,Ожидание) экспорт типЧто = ТипЗнч(Проверяемое); типСЧем = ТипЗнч(Ожидание); если типЧто <> типСЧем тогда Возврат Ошибка("Типы различаются. Первый - "+типЧто+", Второй - "+типСЧем); конецЕсли;

// типы равны!
если ПримитивныеТипы.СодержитТип(типЧто) тогда
    Если ЛогическоеВыражениеВерно(x = y) тогда
        Возврат Ок(Истина);
    Иначе
        Возврат Ошибка(СформироватьСообщениеОбОшибке(х, "РАВНО (" + у + ")."));
        Возврат ложь;
    КонецЕсли;
конецЕсли;

КонецФункции

Вызывающая функция анализирует что вернули по полю Тип, если 0 - то сравнение прошло с ошибкой, в поле значение - описание ошибки (может быть строка, может еще что), Если 1 - то сравнение прошло успешно.

Остается вопрос сообщений. Предположим даны 2 структуры - х = Новый Структура("Поле1",1); у = Новый Структура("Поле1","Поле2"); Сравнение вернет ложь (поля не равны), Текст сообщения может быть таким - "Не равны значения поля 'Поле1' - Ожидалось '"Поле2"', есть '1'", но что выводить для более сложных случаев? Например если так - х = Новый Структура("Поле1",1); х0 = Новый Структура("Поле1",1); у = Новый Структура("Поле1",х0);

Фактически вопрос сводиться к простому - как выводить позицию в коллекции в которой возникла ошибка? что выводить в ожиданиях и результате?

wwall avatar Jan 25 '16 10:01 wwall

АПИ утверждений БДД не нарушается, это хорошо. @wizi4d Что скажешь?

artbear avatar Jan 25 '16 10:01 artbear

что выводить для более сложных случаев? Например если так - 
х = Новый Структура("Поле1",1);
х0 = Новый Структура("Поле1",1);
у = Новый Структура("Поле1",х0);

Фактически вопрос сводиться к простому - как выводить позицию в коллекции, в которой возникла ошибка? что выводить в ожиданиях и результате? 

В примере непонятно, что с чем сравниваем! если х и у, тогда будет выдано сообщение о разных типах, если х и х0, тогда простое сообщение, указанное у тебя в тексте

artbear avatar Jan 25 '16 10:01 artbear

Главный вопрос сравнения коллекций - что делать, если в одной коллекции есть элементы, которой нет во второй коллекции. Эти коллекции равны или не равны? Тут возможны несколько поведений

artbear avatar Jan 25 '16 10:01 artbear

@kuntashov Твое мнение также интересно (в свете тест-раннера для 1скрипт)

artbear avatar Jan 25 '16 10:01 artbear

сравниваем х и у. А какое сообщение будет? "Не равны значения поля 'Поле1' - Ожидалось '1', есть ???? а вот что вместо есть ставить? Я пока вижу так "Не равны значения поля 'Поле1' - Ожидалось '1', есть 'Структура' Или "Не равны значения поля 'Поле1' - Ожидалось '1', есть ХХХ Вместо ХХХ - сериализованное в json значение структуры у.

wwall avatar Jan 25 '16 10:01 wwall

Главный вопрос сравнения коллекций - что делать, если в одной коллекции есть элементы, >которой нет во второй коллекции. Эти коллекции равны или не равны?

Для начала считаем что не равны, потому что иначе придется менять инициализацию тестов, и переменные контекста в тестирование добавлять

wwall avatar Jan 25 '16 10:01 wwall

"Не равны значения поля 'Поле1' - Ожидалось '1', есть ???? 
а вот что вместо есть ставить? 
Я пока вижу так 
"Не равны значения поля 'Поле1' - Ожидалось '1', есть 'Структура'
Или 
"Не равны значения поля 'Поле1' - Ожидалось '1', есть ХХХ 
Вместо ХХХ - сериализованное в json значение структуры у. 

ИМХО сериализовать и показывать лучше только первый уровень коллекции для исключения слишком большого вывода.

artbear avatar Jan 25 '16 10:01 artbear

Для начала считаем что не равны, потому что иначе придется менять инициализацию тестов, и переменные контекста в тестирование добавлять

не понял. Поясни на примере

artbear avatar Jan 25 '16 10:01 artbear

Процедура Инициализация(КонтекстЯдраПараметр) Экспорт
    КонтекстЯдра = КонтекстЯдраПараметр;
    Ожидаем = КонтекстЯдра.Плагин("УтвержденияBDD",ЭтотОбъект); // **Добавили ссылку на наш объект который тестируем**
КонецПроцедуры

Функция ХитраяПроверка(х,у) экспорт /// **Эту функцию используем для тестирования**
    Если х.Поле1 = у.Поле0 тогда
        Возрат Ожидание.СоздатьОк(Истина);
   иначе
        Возрат Ожидание.СоздатьОшибка("Не равно никак");
  конецесли;
конецфункии

Процедура ТестПроверкиРавенстваСтруктур() Экспорт

СтруктураПроверки = новый Структура;
СтруктураПроверки.Вставить("Поле",1);
СтруктураПроверки.Вставить("Поле2",новый Структура("Поле3",4));

СтруктураПроверки2 = новый Структура;
СтруктураПроверки2.Вставить("Поле0",0);
СтруктураПроверки2.Вставить("Поле",1);
СтруктураПроверки2.Вставить("Поле2",новый Структура("Поле3",4));
Ожидаем.Что(СтруктураПроверки).СвояПроверка("ХитраяПроверка",СтруктураПроверки2); // **Вызов нашей функции через прокладку**
КонецПроцедуры 

Примерно так Вообще об этом надо будет думать, так как тестировать можно не только коллекции, но и всякие хитриые штуки - типа COMобъектов, XDTO и прочей чуши

wwall avatar Jan 25 '16 10:01 wwall

Главный вопрос сравнения коллекций - что делать, если в одной коллекции есть элементы, которой нет во второй коллекции.

Возможно, стоит сделать два метода: КоллекцииРавны(ПроверяемаяКоллекция, ЭталоннаяКоллекция) (для Структур и Соответствий) и КоллекцияЯвляетсяПодмножеством(ПроверяемаяКоллекция, ЭталоннаяКоллекция)

Второй случай как раз, когда по составу ключей из ПроверяемаяКоллекция она совпадает с ЭталоннойКоллекцией, но в ЭталоннойКоллекции есть и другие ключи. При этом к вложенным коллекциям должна применяться та же стратегия.

kuntashov avatar Jan 25 '16 10:01 kuntashov

Ребята, оформляйте код в блок из тройных обратных одинарных кавычек (которая буква Ё в русской раскладке).

kuntashov avatar Jan 25 '16 10:01 kuntashov

@kuntashov

Возможно, стоит сделать два метода: КоллекцииРавны(ПроверяемаяКоллекция, ЭталоннаяКоллекция) (для Структур и Соответствий) и КоллекцияЯвляетсяПодмножеством(ПроверяемаяКоллекция, ЭталоннаяКоллекция)

Я уже сталкивался с подобными проблемами при разработке/использовании утверждений по сравнению таблиц/печатных форм. Подобные проблемы есть не только для Структур/соответствий, но и для таблиц значений и деревьев. Что делать, если в одной из таблиц/деревьев есть лишние колонки? здесь использование термина подмножество вроде не звучит

artbear avatar Jan 25 '16 10:01 artbear

тут настраиваемая проверка. Либо пользователь текстом сам пишет, а проверка через выполнить/вычислить это вычисляет, либо - пользователь пишет свой сравниватель с реализацией интерфейса Утверждений, затем регистрирует в коллекции сравнвателей и может вызывать потом себя

wwall avatar Jan 25 '16 10:01 wwall

но и для таблиц значений и деревьев.

  • ТаблицаЗначений - это индексированная коллекция строк.
  • КоллекцияКолонокТаблицыЗначений - это индексированная коллекция объектов типа КолонкаТаблицыЗначений
  • ДеревоЗначений - это объект, свойство Строки которого - КоллекцияСтрокДереваЗначений - также индексированная коллекция и т.п.

Применение термина подмножество мне кажется уместным для любой коллекции.

Если уж заниматься детально этой задачей, то для индексированных коллекций, например, массивов, важно также - они равны, т.е. у них одинаков И состав И порядок или они эквивалентны (т.е. у них одинаков состав, а порядок элементов может отличаться).

Почему тебе не нравится термин подмножество?

kuntashov avatar Jan 25 '16 11:01 kuntashov

@kuntashov Лады, по подмножеству я согласен. ИМХО пока предлагаю работать над равенством.

Эквивалентность ИМХО нужно выделить в соседнюю задачу, если у кого-то возникнет необходимость, может сделать.

artbear avatar Jan 25 '16 12:01 artbear

@wwall ИМХО ты смешиваешь 2 задачи: 1 сравнение коллекций 2 АПИ пользовательских функций-утверждений

ИМХО удобнее их обсуждать отдельно.

artbear avatar Jan 25 '16 12:01 artbear

@artbear согласен, будет потребность - сдела(ют|ем).

kuntashov avatar Jan 25 '16 12:01 kuntashov

В первом приближении готово. Отправил Артуру, после того как выложит - можно критиковать. Доделаю на неделе. Мне пока только сравнение структур нужно

wwall avatar Jan 25 '16 13:01 wwall

Мне не нравится, что метод Равно превратиться в монстра перегруженного функционалом. Можем стоит новый метод сделать, аналог equal в java и sharp?

wizi4d avatar Jan 26 '16 11:01 wizi4d

@wizi4d Я согласен, что монстр и перегрузка это плохо. Но если с точки зрения для пользователя API метода Равно не изменится, ИМХО это будет хорошо.

artbear avatar Jan 26 '16 13:01 artbear

Этого монстра никто не видит. Видят только результат работы - равно или нет. И второе - если плодить методы - то что мешает тогда явно писать ТаблицаЗначенийРавно(), ДеревоЗначенийРавно(), МассивРавно() ?

wwall avatar Jan 26 '16 13:01 wwall

Когда я писал про монстра, я в первую очередь говорил про код и возможность его поддерживать и модифицировать. То что предлагается существенно повысит цикломатическую сложность. В других языках, например java или c#, проверка равенства подразумевает исключительно проверку одинаковости ссылок на объект. Если перекроить метод Равно, то возможность такой проверки исчезнет. Для приведенного сценария используется не проверка на равенство, а проверка эквивалентности (equal). Вот это я и предлагаю сделать:

Ожидаем.Что(Коллекция1).Эквивалентна(Коллекция2);

wizi4d avatar Jan 26 '16 14:01 wizi4d

Я не против нового метода.

Но мы уже выше обсуждали:

Если уж заниматься детально этой задачей, то для индексированных коллекций, например, массивов, важно также - они равны, т.е. у них одинаков И состав И порядок или они эквивалентны (т.е. у них одинаков состав, а порядок элементов может отличаться).

Как мы будем разделять понятия равно и эквивалентность для коллекций ?

artbear avatar Jan 26 '16 14:01 artbear

Добавил пулл-реквест #589 c кодом от @wwall Предлагаю обсудить.

artbear avatar Jan 26 '16 15:01 artbear