суббота, 29 мая 2010 г.

[work] Тестовое задание, которое я давал кандидатам на должность C++ программиста

В продолжение разговоров о тестовых заданиях перед собеседованием (часть I, часть II, часть III) публикую решение той задачи, которую я до недавнего времени давал всем кандидатам на должность C++ программиста. Спецификация задачи в том виде, в котором я ее отсылал кандидатам, находится под катом.

Через один-два дня я опубликую свои комментарии по этой задаче: почему она мне нравится, что она показывает, какие качества разработчика она, на самом-то деле, раскрывает и т.д.

Введение

Есть множество текстовых файлов (исходных текстов программ) в которые нужно вставить текст лицензионного соглашения. Например, был файл:

#include <iostream>

int
main()
   {
      std::cout << "Hello, world!" << std::endl;
   }

из которого должен быть получен файл:

/*
   Copyright 2004 Вася Пупкин
*/
#include <iostream>

int
main()
   {
      std::cout << "Hello, world!" << std::endl;
   }

Так же, должна быть необходимость смены лицензионной информации. Т.е. заменить существующий фрагмент на новый фрагмент. Например, в приведенном выше тексте сменить лицензионную информацию на:

/*
   Copyright 2004 Вася Пупкин
   Copyright 1982-2004 Б.Страуструп
*/

А так же должна быть возможность изъятия лициензионной информации. Например,
в приведенном примере вернуть текст программы к первоначальному виду.

Спецификация

Должно быть создано консольное приложение с именем licenseins, которое получает все аргументы из командной строки. Параметры командной строки должны задаваться в двух формах: короткой (начинаются с дефиса, за которым следует один символ) или длинной (начинаются с двух дефисов, за которым следует идентификатор произвольной длины). Должны поддерживаться следующие аргументы:

  • -m {ins|del|chanege} (--mode {ins|del|change})
    режим работы приложения:
    • ins -- вставка лицензионной информации в начало файла;
    • del -- изъятие лицензионной информации из файла;
    • change -- замена старой лицензионной информации на новую. В этом режиме на вход приложения должно быть передано два имени файлов с лицензионной информацией: старый текст, который должен быть изъят, и новый текст.
  • -f <имя> (--file <имя>)
    задает имя одного файла, в котором нужно выполнять преобразование. В случае, если должны быть обработаны несколько файлов, для каждого файла должен быть указан свой аргумент -f (—file). Имена файлов должны указываться без wildcard-символов (т.е. без * и ?).
  • -l <имя> (--license <имя>)
    задает имя файла, в котором находится текст лицензионной информации для вставки или удаления из файла.
  • -o <имя> (--old <имя>)
    задает имя файла, в котором находится текст старой лицензии. Этот аргумент может использоваться только в режиме change.
  • -h (—help)
    выдача справки об использовании программы.

Приложение, запущенное без аргументов, должно вести себя так, как будто ему задан один аргумент -h (—help).

Например:

1. Вставка лицензионной информации из файла copying2003 в файлы interface.hpp, interface.cpp:

$ licenseins --file interface.cpp --file interface.hpp --license copying2003 -m ins

2. Замена лицензионной информации в файле interface.cpp на новую из файла copying2004:

$ licenseins -f interface.cpp -l copying2004 --mode change --old copying2003

3. Изъятие лицензионной информации из файла interface.hpp

$ licenseins --mode del -f interface.hpp --license copying2003

Приложение должно помещать новое содержимое модифицированного файла в файл с тем же самым именем. Не должно оставаться никаких back-up файлов, если приложение завершило свою работу успешно. Нужно реализовать возможность восстановления содержимого файла, если приложение завершилось аварийно (например, исходный файл переименовывается в *.tmp, создается новый файл с исходным именем, в него записывается новое содержимое, *.tmp уничтожается). Политика обеспечения восстановления после сбоев не специфицируется и может быть выбрана по усмотрению разработчика. Если для выбранной политики требуются дополнительные аргументы (например, путь для сохранения временных файлов), то они могут быть добавлены разработчиком по своему усмотрению, но должны допускать две формы записи.

Приложение должно завершаться с нулевым кодом возврата, если все преобразования завершились успешно. В противном случае приложение должно возвращать не нулевой код.

Бонусное условие

Необходимо предусмотреть возможность задания большого количества аргументов -f (--file) (больше, чем может поместиться в командной строке) путем поддержки т.н. response-файлов. Если в командной строке указан аргумент вида @<имя>, то <имя> нужно интерпретировать как имя файла, в котором задаются не поместившиеся в командную строку аргументы. В response файле аргументы не обязательно должны перечисляться в одну строку: они могут быть расположенны по одному в одной строке, по несколько в одной строке и т.д. В response-файле могут быть пустые строки. В response-файле не может быть ссылок на другие response-файлы – это ошибка. В командной строке может быть указано несколько response-файлов.

Примечание. Реализация response-файлов необязательна. Если поддержка response-файлов будет сделана – очень хорошо. Если нет – не страшно.

Требования

Требования к оформлению исходных текстов

В данной задаче не предъявляются.

Требования к языку

Приложение должно быть разработано на языке C++. Стиль разработки не оговаривается -- приложение может быть разработано в объектно-ориентированном или процедурном стиле. Разработчик должен выбрать тот стиль, который обеспечивает ему наибольшую скорость разработки приложения.

Требования к используемым библиотекам

Должны использоваться только стандартные библиотеки C и C++. Если у кого-то есть собственные библиотеки, которые могут упростить написание приложения (например, средства разбора аргументов командной строки или высокоуровневые операции ввода-вывода в файлы), то они могут быть использованы при выполнении следующих условий:

1) библиотеки написаны с использованием только стандартных библиотек C и C++;

2) исходные тексты библиотек включены в состав исходных текстов приложения.

Другие условия и ограничения

Размеры файлов

Можно предполагать, что файл с текстом лицензии будет помещаться в оперативной памяти.

Нельзя расчитывать на то, что каждый из исходных текстов может быть загружен полностью в оперативную память. Например, могут быть большие XML-файлы с "снимками" какой-либо БД.

Концы строк

На платформе Windows в конце каждой строки текстового файла используется маркер из двух символов: \r\n (возврат каретки, первод строки). На платформе Unix в качестве маркера используется один символ: \n. На платформе Mac используется один символ: \r.

При поиске места вхождения лицензионной информации в исходном файле необходимо игнорировать различия в маркерах концов строк.

При вставке текста лицензионной информации нужно использовать те маркеры, которые были в файле текста лицензии.

Отправить комментарий