diff --git a/Makefile b/Makefile index 7b2acbf..460eb9c 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,5 @@ pyvows: @env PYTHONPATH=$$PYTHONPATH:. pyvows --cover --cover_package=django_pyvows --cover_threshold=100 vows/ + +db: + @env PYTHONPATH=$$PYTHONPATH:. mysql -u root -e 'CREATE DATABASE IF NOT EXISTS django_pyvows' && python vows/sandbox/manage.py syncdb diff --git a/django_pyvows/context.py b/django_pyvows/context.py index 77ea8f8..5f66d06 100644 --- a/django_pyvows/context.py +++ b/django_pyvows/context.py @@ -12,17 +12,19 @@ import os from pyvows import Vows from django_pyvows.assertions import Url +from django_pyvows.model_assertions import Model from django.http import HttpRequest class DjangoContext(Vows.Context): + @classmethod + def _start_environment(cls, settings_path): + if not settings_path: + raise RuntimeError('The settings_path argument is required.') + os.environ['DJANGO_SETTINGS_MODULE'] = settings_path def __init__(self, parent): super(DjangoContext, self).__init__(parent) - if not hasattr(self, '_get_settings'): - raise RuntimeError('The context %s needs a _get_settings method that returns the DJANGO_SETTINGS_MODULE environment variable value.' % self.__class__.__name__) - os.environ['DJANGO_SETTINGS_MODULE'] = self._get_settings() - #Gotta set settings environment variable first from django.test.utils import setup_test_environment #, teardown_test_environment setup_test_environment() @@ -33,11 +35,5 @@ class DjangoContext(Vows.Context): def _request(self, **kw): return HttpRequest(**kw) -class DjangoSubContext(Vows.Context): - - def _url(self, path): - return self.parent._url(path) - - def _request(self, **kw): - return self.parent._request(**kw) - + def _model(self, model_class): + return Model(self, model_class) diff --git a/django_pyvows/model_assertions.py b/django_pyvows/model_assertions.py new file mode 100644 index 0000000..e1d94c6 --- /dev/null +++ b/django_pyvows/model_assertions.py @@ -0,0 +1,72 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# django-pyvows extensions +# https://github.com/rafaelcaricio/django-pyvows + +# Licensed under the MIT license: +# http://www.opensource.org/licenses/mit-license +# Copyright (c) 2011 Rafael Caricio rafael@caricio.com + +from pyvows import Vows, expect + +class Model(object): + def __init__(self, context, model): + self.context = context + self.model = model + +@Vows.assertion +def to_be_cruddable(topic): + import django.db.models.fields as fields + instance = __create_instance(topic) + + assert instance, "An instance could not be created for model %s" % topic.model.__name__ + + retrieved = topic.model.objects.get(id=instance.id) + assert retrieved.id == instance.id, "An instance could not be retrieved for model %s with id %d" % (topic.model.__name__, instance.id) + + updated = __update_instance(topic, retrieved) + + for field, value in topic.model._meta._field_cache: + if field.__class__ == fields.AutoField: + continue + + assert getattr(updated, field.name) != getattr(instance, field.name), "The instance should have been updated but the field %s is the same in both the original instance and the updated one (%s)." % (field.name, getattr(updated, field.name)) + +def __create_instance(topic): + import django.db.models.fields as fields + arguments = {} + for field, value in topic.model._meta._field_cache: + if field.__class__ == fields.AutoField: + continue + + if field.__class__ == fields.CharField: + __add_char_value_for(field, None, arguments) + + return topic.model.objects.create(**arguments) + +def __update_instance(topic, instance): + import django.db.models.fields as fields + arguments = {} + for field, value in topic.model._meta._field_cache: + if field.__class__ == fields.AutoField: + continue + + if field.__class__ == fields.CharField: + __add_char_value_for(field, instance, arguments) + + for key, value in arguments.iteritems(): + setattr(instance, key, value) + + instance.save() + return instance + +def __add_char_value_for(field, instance, arguments): + value = "monty python" + if instance: + value = getattr(instance, field.name) + '2' + if field.max_length: + if instance: + value = value[:len(value) - 2] + '2' + value = (value * field.max_length)[:field.max_length] + arguments[field.name] = value diff --git a/vows/context_vows.py b/vows/context_vows.py index 1443fce..bca8ebd 100644 --- a/vows/context_vows.py +++ b/vows/context_vows.py @@ -12,14 +12,11 @@ from pyvows import Vows, expect from django_pyvows.context import DjangoContext -class DjangoFailedContext(DjangoContext): - pass - @Vows.batch class ContextTest(Vows.Context): def topic(self): - return DjangoFailedContext(self) + return DjangoContext._start_environment(None) def should_be_an_error(self, topic): expect(topic).to_be_an_error() @@ -28,4 +25,4 @@ class ContextTest(Vows.Context): expect(topic).to_be_an_error_like(RuntimeError) def should_have_nice_error_message(self, topic): - expect(topic).to_have_an_error_message_of('The context DjangoFailedContext needs a _get_settings method that returns the DJANGO_SETTINGS_MODULE environment variable value.') + expect(topic).to_have_an_error_message_of('The settings_path argument is required.') diff --git a/vows/model_vows.py b/vows/model_vows.py new file mode 100644 index 0000000..baa8e82 --- /dev/null +++ b/vows/model_vows.py @@ -0,0 +1,29 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# django-pyvows extensions +# https://github.com/rafaelcaricio/django-pyvows + +# Licensed under the MIT license: +# http://www.opensource.org/licenses/mit-license +# Copyright (c) 2011 Rafael Caricio rafael@caricio.com + +from pyvows import Vows, expect +from django_pyvows.context import DjangoContext + +DjangoContext._start_environment('sandbox.settings') + +from sandbox.main.models import StringModel + +@Vows.batch +class ModelVows(Vows.Context): + + class MainModel(DjangoContext): + + def topic(self): + return self._model(StringModel) + + def should_be_cruddable_when_model_only_has_a_string(self, topic): + expect(topic).to_be_cruddable() + + diff --git a/vows/sandbox/main/models.py b/vows/sandbox/main/models.py index 71a8362..f1c183e 100644 --- a/vows/sandbox/main/models.py +++ b/vows/sandbox/main/models.py @@ -1,3 +1,14 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# django-pyvows extensions +# https://github.com/rafaelcaricio/django-pyvows + +# Licensed under the MIT license: +# http://www.opensource.org/licenses/mit-license +# Copyright (c) 2011 Rafael Caricio rafael@caricio.com + from django.db import models -# Create your models here. +class StringModel(models.Model): + name = models.CharField(max_length=100) diff --git a/vows/sandbox/settings.py b/vows/sandbox/settings.py index 550f07d..b99e236 100644 --- a/vows/sandbox/settings.py +++ b/vows/sandbox/settings.py @@ -1,3 +1,13 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# django-pyvows extensions +# https://github.com/rafaelcaricio/django-pyvows + +# Licensed under the MIT license: +# http://www.opensource.org/licenses/mit-license +# Copyright (c) 2011 Rafael Caricio rafael@caricio.com + # Django settings for sandbox project. DEBUG = True @@ -11,12 +21,10 @@ MANAGERS = ADMINS DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. - 'NAME': '', # Or path to database file if using sqlite3. - 'USER': '', # Not used with sqlite3. + 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. + 'NAME': 'django_pyvows', # Or path to database file if using sqlite3. + 'USER': 'root', # Not used with sqlite3. 'PASSWORD': '', # Not used with sqlite3. - 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. - 'PORT': '', # Set to empty string for default. Not used with sqlite3. } } @@ -115,6 +123,7 @@ INSTALLED_APPS = ( 'django.contrib.sites', 'django.contrib.messages', 'django.contrib.staticfiles', + 'sandbox.main', # Uncomment the next line to enable the admin: # 'django.contrib.admin', # Uncomment the next line to enable admin documentation: diff --git a/vows/url_vows.py b/vows/url_vows.py index acc2483..d7e705e 100644 --- a/vows/url_vows.py +++ b/vows/url_vows.py @@ -9,17 +9,16 @@ # Copyright (c) 2011 Rafael Caricio rafael@caricio.com from pyvows import Vows, expect -from django_pyvows.context import DjangoContext, DjangoSubContext +from django_pyvows.context import DjangoContext + +DjangoContext._start_environment('sandbox.settings') from sandbox.main.views import home @Vows.batch -class UrlVows(DjangoContext): +class UrlVows(Vows.Context): - def _get_settings(self): - return 'sandbox.settings' - - class Home(DjangoSubContext): + class Home(DjangoContext): def topic(self): return self._url('^$') diff --git a/vows/view_vows.py b/vows/view_vows.py index 10535db..9d89644 100644 --- a/vows/view_vows.py +++ b/vows/view_vows.py @@ -9,18 +9,16 @@ # Copyright (c) 2011 Rafael Caricio rafael@caricio.com from pyvows import Vows, expect -from django_pyvows.context import DjangoContext, DjangoSubContext -from django.http import HttpResponse +from django_pyvows.context import DjangoContext + +DjangoContext._start_environment('sandbox.settings') from sandbox.main.views import home @Vows.batch -class ViewVows(DjangoContext): +class ViewVows(Vows.Context): - def _get_settings(self): - return 'sandbox.settings' - - class Home(DjangoSubContext): + class Home(DjangoContext): def topic(self): return home(self._request())